Esempio n. 1
0
    def test_is_admin(self):
        # Make sure RBAC is enabled for the tests
        cfg.CONF.set_override(name='enable', override=True, group='rbac')

        # Admin user
        self.assertTrue(user_is_admin(user_db=self.admin_user))

        # Regular user
        self.assertFalse(user_is_admin(user_db=self.regular_user))
Esempio n. 2
0
    def test_is_admin(self):
        # Make sure RBAC is enabled for the tests
        cfg.CONF.set_override(name='enable', override=True, group='rbac')

        # Admin user
        self.assertTrue(user_is_admin(user_db=self.admin_user))

        # Regular user
        self.assertFalse(user_is_admin(user_db=self.regular_user))
Esempio n. 3
0
    def get(self, requester_user, auth_info):
        """
        Meta API endpoint wich returns information about the currently authenticated user.

            Handle:
                GET /v1/user
        """

        data = {}

        if cfg.CONF.rbac.enable and requester_user:
            role_dbs = get_roles_for_user(user_db=requester_user)
            roles = [role_db.name for role_db in role_dbs]
        else:
            roles = []

        data = {
            'username': requester_user.name,
            'authentication': {
                'method': auth_info['method'],
                'location': auth_info['location']
            },
            'rbac': {
                'enabled': cfg.CONF.rbac.enable,
                'roles': roles,
                'is_admin': rbac_utils.user_is_admin(user_db=requester_user)
            }
        }

        if auth_info.get('token_expire', None):
            token_expire = auth_info['token_expire'].strftime(
                '%Y-%m-%dT%H:%M:%SZ')
            data['authentication']['token_expire'] = token_expire

        return data
Esempio n. 4
0
def get_key(key=None, user=None, scope=None, decrypt=False):
    """Retrieve key from KVP store
    """
    if not isinstance(key, six.string_types):
        raise TypeError('Given key is not typeof string.')
    if not isinstance(decrypt, bool):
        raise TypeError('Decrypt parameter is not typeof bool.')

    if not user:
        user = UserDB(cfg.CONF.system_user.user)

    scope, key_id = _derive_scope_and_key(key, user, scope)

    scope = get_datastore_full_scope(scope)

    LOG.debug('get_key scope: %s', scope)

    _validate_scope(scope=scope)

    is_admin = rbac_utils.user_is_admin(user_db=user)

    # User needs to be either admin or requesting item for itself
    _validate_decrypt_query_parameter(decrypt=decrypt,
                                      scope=scope,
                                      is_admin=is_admin,
                                      user=user)

    value = KeyValuePair.get_by_scope_and_name(scope, key_id)

    if value:
        return deserialize_key_value(value.value, decrypt)

    return None
Esempio n. 5
0
    def test_feature_flag_returns_false_on_rbac_enabled(self):
        cfg.CONF.set_override(name="enable", override=True, group="rbac")

        # TODO: Enable once checks are implemented
        return
        result = utils.user_is_admin(user_db=self.mocks["user_db"])
        self.assertFalse(result)
Esempio n. 6
0
File: user.py Progetto: lyandut/st2
    def get(self, requester_user, auth_info):
        """
        Meta API endpoint wich returns information about the currently authenticated user.

            Handle:
                GET /v1/user
        """

        data = {}

        if cfg.CONF.rbac.enable and requester_user:
            role_dbs = get_roles_for_user(user_db=requester_user)
            roles = [role_db.name for role_db in role_dbs]
        else:
            roles = []

        data = {
            'username': requester_user.name,
            'authentication': {
                'method': auth_info['method'],
                'location': auth_info['location']
            },
            'rbac': {
                'enabled': cfg.CONF.rbac.enable,
                'roles': roles,
                'is_admin': rbac_utils.user_is_admin(user_db=requester_user)
            }
        }

        if auth_info.get('token_expire', None):
            token_expire = auth_info['token_expire'].strftime('%Y-%m-%dT%H:%M:%SZ')
            data['authentication']['token_expire'] = token_expire

        return data
Esempio n. 7
0
    def test_feature_flag_returns_false_on_rbac_enabled(self):
        cfg.CONF.set_override(name='enable', override=True, group='rbac')

        # TODO: Enable once checks are implemented
        return
        result = utils.user_is_admin(user_db=self.mocks['user_db'])
        self.assertFalse(result)
Esempio n. 8
0
    def get_all(self, requester_user, prefix=None, scope=FULL_SYSTEM_SCOPE, user=None,
                decrypt=False, sort=None, offset=0, limit=None, **raw_filters):
        """
            List all keys.

            Handles requests:
                GET /keys/
        """
        if not scope:
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)
        is_all_scope = (scope == ALL_SCOPE)

        is_admin = rbac_utils.user_is_admin(user_db=requester_user)
        if is_all_scope and not is_admin:
            msg = '"all" scope requires administrator access'
            raise AccessDeniedError(message=msg, user_db=requester_user)

        # User needs to be either admin or requesting items for themselves
        self._validate_decrypt_query_parameter(decrypt=decrypt, scope=scope, is_admin=is_admin,
                                               requester_user=requester_user)

        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
                                                             user=user)

        from_model_kwargs = {'mask_secrets': not decrypt}

        if scope and scope not in ALL_SCOPE:
            self._validate_scope(scope=scope)
            raw_filters['scope'] = scope

        if scope == USER_SCOPE or scope == FULL_USER_SCOPE:
            # Make sure we only returned values scoped to current user
            if prefix:
                prefix = get_key_reference(name=prefix, scope=scope, user=user)
            else:
                prefix = get_key_reference(name='', scope=scope, user=user)

        raw_filters['prefix'] = prefix

        kvp_apis = super(KeyValuePairController, self)._get_all(from_model_kwargs=from_model_kwargs,
                                                                sort=sort,
                                                                offset=offset,
                                                                limit=limit,
                                                                raw_filters=raw_filters,
                                                                requester_user=requester_user)
        return kvp_apis
Esempio n. 9
0
    def get_all(self, requester_user, prefix=None, scope=FULL_SYSTEM_SCOPE, user=None,
                decrypt=False, sort=None, offset=0, limit=None, **raw_filters):
        """
            List all keys.

            Handles requests:
                GET /keys/
        """
        if not scope:
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)
        is_all_scope = (scope == ALL_SCOPE)

        is_admin = rbac_utils.user_is_admin(user_db=requester_user)
        if is_all_scope and not is_admin:
            msg = '"all" scope requires administrator access'
            raise AccessDeniedError(message=msg, user_db=requester_user)

        # User needs to be either admin or requesting items for themselves
        self._validate_decrypt_query_parameter(decrypt=decrypt, scope=scope, is_admin=is_admin,
                                               requester_user=requester_user)

        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
                                                             user=user)

        from_model_kwargs = {'mask_secrets': not decrypt}

        if scope and scope not in ALL_SCOPE:
            self._validate_scope(scope=scope)
            raw_filters['scope'] = scope

        if scope == USER_SCOPE or scope == FULL_USER_SCOPE:
            # Make sure we only returned values scoped to current user
            if prefix:
                prefix = get_key_reference(name=prefix, scope=scope, user=user)
            else:
                prefix = get_key_reference(name='', scope=scope, user=user)

        raw_filters['prefix'] = prefix

        kvp_apis = super(KeyValuePairController, self)._get_all(from_model_kwargs=from_model_kwargs,
                                                                sort=sort,
                                                                offset=offset,
                                                                limit=limit,
                                                                raw_filters=raw_filters)
        return kvp_apis
Esempio n. 10
0
    def _validate_all_scope(self, scope, requester_user):
        """
        Validate that "all" scope can only be provided by admins on RBAC installations.
        """
        scope = get_datastore_full_scope(scope)
        is_all_scope = (scope == ALL_SCOPE)
        is_admin = rbac_utils.user_is_admin(user_db=requester_user)

        if is_all_scope and not is_admin:
            msg = '"all" scope requires administrator access'
            raise AccessDeniedError(message=msg, user_db=requester_user)
Esempio n. 11
0
    def _validate_decrypt_query_parameter(self, decrypt, scope, requester_user):
        """
        Validate that the provider user is either admin or requesting to decrypt value for
        themselves.
        """
        is_admin = rbac_utils.user_is_admin(user_db=requester_user)
        is_user_scope = (scope == USER_SCOPE or scope == FULL_USER_SCOPE)

        if decrypt and (not is_user_scope and not is_admin):
            msg = 'Decrypt option requires administrator access'
            raise AccessDeniedError(message=msg, user_db=requester_user)
Esempio n. 12
0
File: base.py Progetto: lyandut/st2
    def _get_mask_secrets(self, requester_user, show_secrets=None):
        """
        Return a value for mask_secrets which can be used in masking secret properties
        to be retruned by any API. The default value is as per the config however admin
        users have the ability to override by passing in a special query parameter
        ?show_secrets=True.

        :rtype: ``bool``
        """
        mask_secrets = cfg.CONF.api.mask_secrets

        if show_secrets and rbac_utils.user_is_admin(user_db=requester_user):
            mask_secrets = False

        return mask_secrets
Esempio n. 13
0
    def _get_mask_secrets(self, requester_user, show_secrets=None):
        """
        Return a value for mask_secrets which can be used in masking secret properties
        to be retruned by any API. The default value is as per the config however admin
        users have the ability to override by passing in a special query parameter
        ?show_secrets=True.

        :rtype: ``bool``
        """
        mask_secrets = cfg.CONF.api.mask_secrets

        if show_secrets and rbac_utils.user_is_admin(user_db=requester_user):
            mask_secrets = False

        return mask_secrets
Esempio n. 14
0
    def get_one(self,
                name,
                requester_user,
                scope=FULL_SYSTEM_SCOPE,
                user=None,
                decrypt=False):
        """
            List key by name.

            Handle:
                GET /keys/key1
        """
        if not scope:
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)
        self._validate_scope(scope=scope)

        is_admin = rbac_utils.user_is_admin(user_db=requester_user)

        # User needs to be either admin or requesting item for itself
        self._validate_decrypt_query_parameter(decrypt=decrypt,
                                               scope=scope,
                                               is_admin=is_admin,
                                               requester_user=requester_user)

        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(
            user_db=requester_user, user=user)

        key_ref = get_key_reference(scope=scope, name=name, user=user)
        from_model_kwargs = {'mask_secrets': not decrypt}
        kvp_api = self._get_one_by_scope_and_name(
            name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs)

        return kvp_api
Esempio n. 15
0
    def get_one(self, name, requester_user, scope=FULL_SYSTEM_SCOPE, user=None, decrypt=False):
        """
            List key by name.

            Handle:
                GET /keys/key1
        """
        if not scope:
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)
        self._validate_scope(scope=scope)

        is_admin = rbac_utils.user_is_admin(user_db=requester_user)

        # User needs to be either admin or requesting item for itself
        self._validate_decrypt_query_parameter(decrypt=decrypt, scope=scope, is_admin=is_admin,
                                               requester_user=requester_user)

        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
                                                             user=user)

        key_ref = get_key_reference(scope=scope, name=name, user=user)
        from_model_kwargs = {'mask_secrets': not decrypt}
        kvp_api = self._get_one_by_scope_and_name(
            name=key_ref,
            scope=scope,
            from_model_kwargs=from_model_kwargs
        )

        return kvp_api
Esempio n. 16
0
    def resource_model_filter(self, model, instance, requester_user=None, **from_model_kwargs):
        # RBAC or permission isolation is disabled, bail out
        if not (cfg.CONF.rbac.enable and cfg.CONF.rbac.permission_isolation):
            result = super(BaseResourceIsolationControllerMixin, self).resource_model_filter(
                model=model, instance=instance, requester_user=requester_user,
                **from_model_kwargs)

            return result

        user_is_admin = rbac_utils.user_is_admin(user_db=requester_user)
        user_is_system_user = (requester_user.name == cfg.CONF.system_user.user)

        item = model.from_model(instance, **from_model_kwargs)

        # Admin users and system users can view all the resoruces
        if user_is_admin or user_is_system_user:
            return item

        user = item.context.get('user', None)
        if user and (user == requester_user.name):
            return item

        return None
Esempio n. 17
0
    def resource_model_filter(self, model, instance, requester_user=None, **from_model_kwargs):
        # RBAC or permission isolation is disabled, bail out
        if not (cfg.CONF.rbac.enable and cfg.CONF.rbac.permission_isolation):
            result = super(BaseResourceIsolationControllerMixin, self).resource_model_filter(
                model=model, instance=instance, requester_user=requester_user,
                **from_model_kwargs)

            return result

        user_is_admin = rbac_utils.user_is_admin(user_db=requester_user)
        user_is_system_user = (requester_user.name == cfg.CONF.system_user.user)

        item = model.from_model(instance, **from_model_kwargs)

        # Admin users and system users can view all the resoruces
        if user_is_admin or user_is_system_user:
            return item

        user = item.context.get('user', None)
        if user and (user == requester_user.name):
            return item

        return None
Esempio n. 18
0
def validate_limit_query_param(limit, requester_user=None):
    """
    Validate that the provided value for "limit" query parameter is valid.

    Note: We only perform max_page_size check for non-admin users. Admin users
    can provide arbitrary limit value.
    """
    user_is_admin = rbac_utils.user_is_admin(user_db=requester_user)

    if limit:
        # Display all the results
        if int(limit) == -1:
            if not user_is_admin:
                # Only admins can specify limit -1
                message = (
                    'Administrator access required to be able to specify limit=-1 and '
                    'retrieve all the records')
                raise AccessDeniedError(message=message,
                                        user_db=requester_user)

            return 0
        elif int(limit) <= -2:
            msg = 'Limit, "%s" specified, must be a positive number.' % (limit)
            raise ValueError(msg)
        elif int(limit) > cfg.CONF.api.max_page_size and not user_is_admin:
            msg = ('Limit "%s" specified, maximum value is "%s"' %
                   (limit, cfg.CONF.api.max_page_size))

            raise AccessDeniedError(message=msg, user_db=requester_user)
    # Disable n = 0
    elif limit == 0:
        msg = (
            'Limit, "%s" specified, must be a positive number or -1 for full result set.'
            % (limit))
        raise ValueError(msg)

    return limit
Esempio n. 19
0
def validate_limit_query_param(limit, requester_user=None):
    """
    Validate that the provided value for "limit" query parameter is valid.

    Note: We only perform max_page_size check for non-admin users. Admin users
    can provide arbitrary limit value.
    """
    user_is_admin = rbac_utils.user_is_admin(user_db=requester_user)

    if limit:
        # Display all the results
        if int(limit) == -1:
            if not user_is_admin:
                # Only admins can specify limit -1
                message = ('Administrator access required to be able to specify limit=-1 and '
                           'retrieve all the records')
                raise AccessDeniedError(message=message,
                                        user_db=requester_user)

            return 0
        elif int(limit) <= -2:
            msg = 'Limit, "%s" specified, must be a positive number.' % (limit)
            raise ValueError(msg)
        elif int(limit) > cfg.CONF.api.max_page_size and not user_is_admin:
            msg = ('Limit "%s" specified, maximum value is "%s"' % (limit,
                                                                    cfg.CONF.api.max_page_size))

            raise AccessDeniedError(message=msg,
                                    user_db=requester_user)
    # Disable n = 0
    elif limit == 0:
        msg = ('Limit, "%s" specified, must be a positive number or -1 for full result set.' %
               (limit))
        raise ValueError(msg)

    return limit
Esempio n. 20
0
    def test_is_admin(self):
        # Admin user
        self.assertTrue(user_is_admin(user=self.admin_user))

        # Regular user
        self.assertFalse(user_is_admin(user=self.regular_user))
Esempio n. 21
0
    def test_feature_flag_returns_true_on_rbac_disabled(self):
        # When feature RBAC is disabled, all the functions should return True
        cfg.CONF.set_override(name="enable", override=False, group="rbac")

        result = utils.user_is_admin(user_db=self.mocks["user_db"])
        self.assertTrue(result)
Esempio n. 22
0
    def get_one(self, name, requester_user, scope=FULL_SYSTEM_SCOPE, user=None, decrypt=False):
        """
            List key by name.

            Handle:
                GET /keys/key1
        """
        if not scope:
            # Default to system scope
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)
        self._validate_scope(scope=scope)

        # User needs to be either admin or requesting item for itself
        self._validate_decrypt_query_parameter(decrypt=decrypt, scope=scope,
                                               requester_user=requester_user)

        user_query_param_filter = bool(user)

        current_user = requester_user.name
        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
                                                             user=user,
                                                             require_rbac=True)

        # Additional guard to ensure there is no information leakage across users
        is_admin = rbac_utils.user_is_admin(user_db=requester_user)

        if is_admin and user_query_param_filter:
            # Retrieve values scoped to the provided user
            user_scope_prefix = get_key_reference(name=name, scope=USER_SCOPE, user=user)
        else:
            # RBAC not enabled or user is not an admin, retrieve user scoped values for the
            # current user
            user_scope_prefix = get_key_reference(name=name, scope=USER_SCOPE,
                                                  user=current_user)

        if scope == FULL_USER_SCOPE:
            key_ref = user_scope_prefix
        elif scope == FULL_SYSTEM_SCOPE:
            key_ref = get_key_reference(scope=FULL_SYSTEM_SCOPE, name=name, user=user)
        else:
            raise ValueError('Invalid scope: %s' % (scope))

        from_model_kwargs = {'mask_secrets': not decrypt}
        kvp_api = self._get_one_by_scope_and_name(
            name=key_ref,
            scope=scope,
            from_model_kwargs=from_model_kwargs
        )

        return kvp_api
Esempio n. 23
0
 def _validate_encrypted_query_parameter(self, encrypted, scope, requester_user):
     is_admin = rbac_utils.user_is_admin(user_db=requester_user)
     if encrypted and not is_admin:
         msg = 'Pre-encrypted option requires administrator access'
         raise AccessDeniedError(message=msg, user_db=requester_user)
Esempio n. 24
0
    def get_all(self, requester_user, prefix=None, scope=FULL_SYSTEM_SCOPE, user=None,
                decrypt=False, sort=None, offset=0, limit=None, **raw_filters):
        """
            List all keys.

            Handles requests:
                GET /keys/
        """
        if not scope:
            # Default to system scope
            scope = FULL_SYSTEM_SCOPE

        if user:
            # Providing a user implies a user scope
            scope = FULL_USER_SCOPE

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        scope = get_datastore_full_scope(scope)

        # "all" scope can only be used by the admins (on RBAC installations)
        self._validate_all_scope(scope=scope, requester_user=requester_user)

        # User needs to be either admin or requesting items for themselves
        self._validate_decrypt_query_parameter(decrypt=decrypt, scope=scope,
                                               requester_user=requester_user)

        user_query_param_filter = bool(user)

        current_user = requester_user.name
        user = user or requester_user.name

        # Validate that the authenticated user is admin if user query param is provided
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
                                                             user=user,
                                                             require_rbac=True)

        from_model_kwargs = {'mask_secrets': not decrypt}

        if scope and scope not in ALL_SCOPE:
            self._validate_scope(scope=scope)
            raw_filters['scope'] = scope

        # Set prefix which will be used for user-scoped items.
        # NOTE: It's very important raw_filters['prefix'] is set when requesting user scoped items
        # to avoid information leakage (aka user1 retrieves items for user2)
        is_admin = rbac_utils.user_is_admin(user_db=requester_user)

        if is_admin and user_query_param_filter:
            # Retrieve values scoped to the provided user
            user_scope_prefix = get_key_reference(name=prefix or '', scope=USER_SCOPE, user=user)
        else:
            # RBAC not enabled or user is not an admin, retrieve user scoped values for the
            # current user
            user_scope_prefix = get_key_reference(name=prefix or '', scope=USER_SCOPE,
                                                  user=current_user)

        if scope == ALL_SCOPE:
            # Special case for ALL_SCOPE
            # 1. Retrieve system scoped values
            raw_filters['scope'] = FULL_SYSTEM_SCOPE
            raw_filters['prefix'] = prefix

            assert 'scope' in raw_filters
            kvp_apis_system = super(KeyValuePairController, self)._get_all(
                from_model_kwargs=from_model_kwargs,
                sort=sort,
                offset=offset,
                limit=limit,
                raw_filters=raw_filters,
                requester_user=requester_user)

            # 2. Retrieve user scoped items for current user or for all the users (depending if the
            # authenticated user is admin and if ?user is provided)
            raw_filters['scope'] = FULL_USER_SCOPE

            if cfg.CONF.rbac.enable and is_admin and not user_query_param_filter:
                # Admin user retrieving user-scoped items for all the users
                raw_filters['prefix'] = prefix or ''
            else:
                raw_filters['prefix'] = user_scope_prefix

            assert 'scope' in raw_filters
            assert 'prefix' in raw_filters
            kvp_apis_user = super(KeyValuePairController, self)._get_all(
                from_model_kwargs=from_model_kwargs,
                sort=sort,
                offset=offset,
                limit=limit,
                raw_filters=raw_filters,
                requester_user=requester_user)

            # Combine the result
            kvp_apis = []
            kvp_apis.extend(kvp_apis_system.json or [])
            kvp_apis.extend(kvp_apis_user.json or [])
        elif scope in [USER_SCOPE, FULL_USER_SCOPE]:
            # Make sure we only returned values scoped to current user
            prefix = get_key_reference(name=prefix or '', scope=scope, user=user)
            raw_filters['prefix'] = user_scope_prefix

            assert 'scope' in raw_filters
            assert 'prefix' in raw_filters
            kvp_apis = super(KeyValuePairController, self)._get_all(
                from_model_kwargs=from_model_kwargs,
                sort=sort,
                offset=offset,
                limit=limit,
                raw_filters=raw_filters,
                requester_user=requester_user)
        elif scope in [SYSTEM_SCOPE, FULL_SYSTEM_SCOPE]:
            raw_filters['prefix'] = prefix

            assert 'scope' in raw_filters
            kvp_apis = super(KeyValuePairController, self)._get_all(
                from_model_kwargs=from_model_kwargs,
                sort=sort,
                offset=offset,
                limit=limit,
                raw_filters=raw_filters,
                requester_user=requester_user)
        else:
            raise ValueError('Invalid scope: %s' % (scope))

        return kvp_apis
Esempio n. 25
0
    def test_feature_flag_returns_true_on_rbac_disabled(self):
        # When feature RBAC is disabled, all the functions should return True
        cfg.CONF.set_override(name='enable', override=False, group='rbac')

        result = utils.user_is_admin(user_db=self.mocks['user_db'])
        self.assertTrue(result)