Esempio n. 1
0
    def assert_admin(self, request):
        """Ensure the user is an admin.

        :raises keystone.exception.Unauthorized: if a token could not be
            found/authorized, a user is invalid, or a tenant is
            invalid/not scoped.
        :raises keystone.exception.Forbidden: if the user is not an admin and
            does not have the admin role

        """
        request.assert_authenticated()

        if not request.context.is_admin:
            user_token_ref = utils.get_token_ref(request.context_dict)

            creds = copy.deepcopy(user_token_ref.metadata)

            try:
                creds['user_id'] = user_token_ref.user_id
            except exception.UnexpectedError:
                LOG.debug('Invalid user')
                raise exception.Unauthorized(_('Invalid user'))

            if user_token_ref.project_scoped:
                creds['tenant_id'] = user_token_ref.project_id
            else:
                LOG.debug('Invalid tenant')
                raise exception.Unauthorized(_('Invalid tenant'))

            creds['roles'] = user_token_ref.role_names
            # Accept either is_admin or the admin role
            policy.enforce(creds, 'admin_required', {})
Esempio n. 2
0
def enforce(credentials, action, target):
    """Verifies that the action is valid on the target in this context.

       :param credentials: user credentials
       :param action: string representing the action to be checked, which
                      should be colon separated for clarity.
       :param target: dictionary representing the object of the action
                      for object creation this should be a dictionary
                      representing the location of the object e.g.
                      {'tenant_id': object.tenant_id}
       :raises: `exception.Forbidden` if verification fails.

       Actions should be colon separated for clarity. For example:

        * compute:create_instance
        * compute:attach_volume
        * volume:attach_volume

    """
    init()

    match_list = ('rule:%s' % action,)

    try:
        common_policy.enforce(match_list, target, credentials)
    except common_policy.NotAuthorized:
        raise exception.ForbiddenAction(action=action)
Esempio n. 3
0
    def check_protection(self, request, prep_info, target_attr=None):
        """Provide call protection for complex target attributes.

        As well as including the standard parameters from the original API
        call (which is passed in prep_info), this call will add in any
        additional entities or attributes (passed in target_attr), so that
        they can be referenced by policy rules.

        """
        if request.context.is_admin:
            LOG.warning('RBAC: Bypassing authorization')
        else:
            action = 'identity:%s' % prep_info['f_name']
            # TODO(henry-nash) need to log the target attributes as well
            creds = _build_policy_check_credentials(self, action,
                                                    request.context_dict,
                                                    prep_info['input_attr'])
            # Build the dict the policy engine will check against from both the
            # parameters passed into the call we are protecting (which was
            # stored in the prep_info by protected()), plus the target
            # attributes provided.
            policy_dict = {}
            if target_attr:
                policy_dict = {'target': target_attr}
            policy_dict.update(prep_info['input_attr'])
            if 'filter_attr' in prep_info:
                policy_dict.update(prep_info['filter_attr'])
            policy.enforce(creds, action, utils.flatten_dict(policy_dict))
            LOG.debug('RBAC: Authorization granted')
Esempio n. 4
0
def enforce(credentials, action, target):
    """Verifies that the action is valid on the target in this context.

       :param credentials: user credentials
       :param action: string representing the action to be checked

           this should be colon separated for clarity.
           i.e. compute:create_instance
                compute:attach_volume
                volume:attach_volume

       :param object: dictionary representing the object of the action
                      for object creation this should be a dictionary
                      representing the location of the object e.g.
                      {'tenant_id': object.tenant_id}

       :raises: `exception.Forbidden` if verification fails.

    """
    init()

    match_list = ('rule:%s' % action, )

    try:
        common_policy.enforce(match_list, target, credentials)
    except common_policy.NotAuthorized:
        raise exception.ForbiddenAction(action=action)
Esempio n. 5
0
 def test_ignore_case_role_check(self):
     lowercase_action = "example:lowercase_admin"
     uppercase_action = "example:uppercase_admin"
     # NOTE(dprince): We mix case in the Admin role here to ensure
     # case is ignored
     admin_credentials = {'roles': ['AdMiN']}
     policy.enforce(admin_credentials, lowercase_action, self.target)
     policy.enforce(admin_credentials, uppercase_action, self.target)
Esempio n. 6
0
 def test_templatized_enforcement(self):
     target_mine = {'project_id': 'fake'}
     target_not_mine = {'project_id': 'another'}
     credentials = {'project_id': 'fake', 'roles': []}
     action = "example:my_file"
     policy.enforce(credentials, action, target_mine)
     self.assertRaises(exception.ForbiddenAction, policy.enforce,
                       credentials, action, target_not_mine)
Esempio n. 7
0
 def test_ignore_case_role_check(self):
     lowercase_action = "example:lowercase_admin"
     uppercase_action = "example:uppercase_admin"
     # NOTE(dprince): We mix case in the Admin role here to ensure
     # case is ignored
     admin_credentials = {'roles': ['AdMiN']}
     policy.enforce(admin_credentials, lowercase_action, self.target)
     policy.enforce(admin_credentials, uppercase_action, self.target)
Esempio n. 8
0
 def test_templatized_enforcement(self):
     target_mine = {'project_id': 'fake'}
     target_not_mine = {'project_id': 'another'}
     credentials = {'project_id': 'fake', 'roles': []}
     action = "example:my_file"
     policy.enforce(credentials, action, target_mine)
     self.assertRaises(exception.ForbiddenAction, policy.enforce,
                       credentials, action, target_not_mine)
Esempio n. 9
0
        def inner(self, request, *args, **kwargs):
            request.assert_authenticated()

            if request.context.is_admin:
                LOG.warning('RBAC: Bypassing authorization')
            elif callback is not None:
                prep_info = {'f_name': f.__name__, 'input_attr': kwargs}
                callback(self, request, prep_info, *args, **kwargs)
            else:
                action = 'identity:%s' % f.__name__
                creds = _build_policy_check_credentials(
                    self, action, request.context_dict, kwargs)

                policy_dict = {}

                # Check to see if we need to include the target entity in our
                # policy checks.  We deduce this by seeing if the class has
                # specified a get_member() method and that kwargs contains the
                # appropriate entity id.
                if (hasattr(self, 'get_member_from_driver')
                        and self.get_member_from_driver is not None):
                    key = '%s_id' % self.member_name
                    if key in kwargs:
                        ref = self.get_member_from_driver(kwargs[key])
                        policy_dict['target'] = {self.member_name: ref}

                # TODO(henry-nash): Move this entire code to a member
                # method inside v3 Auth
                if request.context_dict.get('subject_token_id') is not None:
                    window_seconds = self._token_validation_window(request)
                    token_ref = token_model.KeystoneToken(
                        token_id=request.context_dict['subject_token_id'],
                        token_data=self.token_provider_api.validate_token(
                            request.context_dict['subject_token_id'],
                            window_seconds=window_seconds))
                    policy_dict.setdefault('target', {})
                    policy_dict['target'].setdefault(self.member_name, {})
                    policy_dict['target'][self.member_name]['user_id'] = (
                        token_ref.user_id)
                    try:
                        user_domain_id = token_ref.user_domain_id
                    except exception.UnexpectedError:
                        user_domain_id = None
                    if user_domain_id:
                        policy_dict['target'][self.member_name].setdefault(
                            'user', {})
                        policy_dict['target'][
                            self.member_name]['user'].setdefault('domain', {})
                        policy_dict['target'][
                            self.member_name]['user']['domain']['id'] = (
                                user_domain_id)

                # Add in the kwargs, which means that any entity provided as a
                # parameter for calls like create and update will be included.
                policy_dict.update(kwargs)
                policy.enforce(creds, action, utils.flatten_dict(policy_dict))
                LOG.debug('RBAC: Authorization granted')
            return f(self, request, *args, **kwargs)
Esempio n. 10
0
 def test_warning_message_is_logged_if_enforce_scope_is_false(self):
     self.config_fixture.config(group='oslo_policy', enforce_scope=False)
     expected_msg = (
         'Policy foo failed scope check. The token used to make the '
         'request was project scoped but the policy requires [\'system\'] '
         'scope. This behavior may change in the future where using the '
         'intended scope is required')
     with mock.patch('warnings.warn') as mock_warn:
         policy.enforce(self.credentials, self.action, self.target)
         mock_warn.assert_called_once_with(expected_msg)
Esempio n. 11
0
 def test_warning_message_is_logged_if_enforce_scope_is_false(self):
     self.config_fixture.config(group='oslo_policy', enforce_scope=False)
     expected_msg = (
         'Policy foo failed scope check. The token used to make the '
         'request was project scoped but the policy requires [\'system\'] '
         'scope. This behavior may change in the future where using the '
         'intended scope is required'
     )
     with mock.patch('warnings.warn') as mock_warn:
         policy.enforce(self.credentials, self.action, self.target)
         mock_warn.assert_called_once_with(expected_msg)
Esempio n. 12
0
 def test_modified_policy_reloads(self):
     action = "example:test"
     empty_credentials = {}
     with open(self.tmpfilename, "w") as policyfile:
         policyfile.write("""{"example:test": []}""")
     policy.enforce(empty_credentials, action, self.target)
     with open(self.tmpfilename, "w") as policyfile:
         policyfile.write("""{"example:test": ["false:false"]}""")
     policy._ENFORCER.clear()
     self.assertRaises(exception.ForbiddenAction, policy.enforce,
                       empty_credentials, action, self.target)
Esempio n. 13
0
 def test_modified_policy_reloads(self):
     action = "example:test"
     empty_credentials = {}
     with open(self.tmpfilename, "w") as policyfile:
         policyfile.write("""{"example:test": []}""")
     policy.enforce(empty_credentials, action, self.target)
     with open(self.tmpfilename, "w") as policyfile:
         policyfile.write("""{"example:test": ["false:false"]}""")
     policy._ENFORCER.clear()
     self.assertRaises(exception.ForbiddenAction, policy.enforce,
                       empty_credentials, action, self.target)
Esempio n. 14
0
        def wrapper(self, request, **kwargs):
            request.assert_authenticated()

            if not request.context.is_admin:
                # The target dict for the policy check will include:
                #
                # - Any query filter parameters
                # - Data from the main url (which will be in the kwargs
                #   parameter), which although most of our APIs do not utilize,
                #   in theory you could have.
                #

                # First build the dict of filter parameters
                target = dict()
                if filters:
                    for item in filters:
                        if item in request.params:
                            target[item] = request.params[item]

                    LOG.debug('RBAC: Adding query filter params (%s)',
                              (', '.join([
                                  '%s=%s' % (item, target[item])
                                  for item in target
                              ])))

                if 'callback' in callback and callback['callback'] is not None:
                    # A callback has been specified to load additional target
                    # data, so pass it the formal url params as well as the
                    # list of filters, so it can augment these and then call
                    # the check_protection() method.
                    prep_info = {
                        'f_name': f.__name__,
                        'input_attr': kwargs,
                        'filter_attr': target
                    }
                    callback['callback'](self, request, prep_info, **kwargs)
                else:
                    # No callback, so we are going to check the protection here
                    action = 'identity:%s' % f.__name__
                    creds = _build_policy_check_credentials(
                        self, action, request.context_dict, kwargs)
                    # Add in any formal url parameters
                    for key in kwargs:
                        target[key] = kwargs[key]

                    policy.enforce(creds, action, utils.flatten_dict(target))

                    LOG.debug('RBAC: Authorization granted')
            else:
                LOG.warning('RBAC: Bypassing authorization')
            return f(self, request, filters, **kwargs)
Esempio n. 15
0
 def test_enforce_good_action(self):
     action = "example:allowed"
     policy.enforce(self.credentials, action, self.target)
Esempio n. 16
0
 def test_not_found_policy_calls_default(self):
     policy.enforce(self.credentials, "example:noexist", {})
Esempio n. 17
0
 def test_early_OR_enforcement(self):
     action = "example:early_or_success"
     policy.enforce(self.credentials, action, self.target)
Esempio n. 18
0
 def enforce(self, credentials, action, target):
     msg = 'enforce %(action)s: %(credentials)s'
     LOG.debug(msg, {
         'action': action,
         'credentials': credentials})
     policy.enforce(credentials, action, target)
Esempio n. 19
0
 def test_early_OR_enforcement(self):
     action = "example:early_or_success"
     policy.enforce(self.credentials, action, self.target)
Esempio n. 20
0
 def enforce(self, credentials, action, target):
     msg = 'enforce %(action)s: %(credentials)s'
     LOG.debug(msg, {
         'action': action,
         'credentials': credentials})
     policy.enforce(credentials, action, target)
Esempio n. 21
0
 def test_not_found_policy_calls_default(self):
     policy.enforce(self.credentials, "example:noexist", {})
Esempio n. 22
0
 def test_enforce_good_action(self):
     action = "example:allowed"
     policy.enforce(self.credentials, action, self.target)