¡@

Home 

OpenStack Study: property_utils.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright 2013 Rackspace

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

import ConfigParser

import re

try:

from collections import OrderedDict

except ImportError:

from ordereddict import OrderedDict

from oslo.config import cfg

import glance.api.policy

from glance.common import exception

from glance.openstack.common import log as logging

from glance.openstack.common import policy

# NOTE(bourke): The default dict_type is collections.OrderedDict in py27, but

# we must set manually for compatibility with py26

CONFIG = ConfigParser.SafeConfigParser(dict_type=OrderedDict)

LOG = logging.getLogger(__name__)

property_opts = [

cfg.StrOpt('property_protection_file',

default=None,

help=_('The location of the property protection file.')),

cfg.StrOpt('property_protection_rule_format',

default='roles',

help=_('This config value indicates whether "roles" or '

'"policies" are used in the property protection file.')),

]

CONF = cfg.CONF

CONF.register_opts(property_opts)

# NOTE (spredzy): Due to the particularly lengthy name of the exception

# and the number of occurrence it is raise in this file, a variable is

# created

InvalidPropProtectConf = exception.InvalidPropertyProtectionConfiguration

**** CubicPower OpenStack Study ****

def is_property_protection_enabled():

    if CONF.property_protection_file:

        return True

    return False

**** CubicPower OpenStack Study ****

class PropertyRules(object):

**** CubicPower OpenStack Study ****

    def __init__(self, policy_enforcer=None):

        self.rules = []

        self.prop_exp_mapping = {}

        self.policies = []

        self.policy_enforcer = policy_enforcer or glance.api.policy.Enforcer()

        self.prop_prot_rule_format = CONF.property_protection_rule_format

        self.prop_prot_rule_format = self.prop_prot_rule_format.lower()

        self._load_rules()

**** CubicPower OpenStack Study ****

    def _load_rules(self):

        try:

            conf_file = CONF.find_file(CONF.property_protection_file)

            CONFIG.read(conf_file)

        except Exception as e:

            msg = (_("Couldn't find property protection file %(file)s: "

                     "%(error)s.") % {'file': CONF.property_protection_file,

                                      'error': e})

            LOG.error(msg)

            raise InvalidPropProtectConf()

        if self.prop_prot_rule_format not in ['policies', 'roles']:

            msg = _("Invalid value '%s' for "

                    "'property_protection_rule_format'. "

                    "The permitted values are "

                    "'roles' and 'policies'") % self.prop_prot_rule_format

            LOG.error(msg)

            raise InvalidPropProtectConf()

        operations = ['create', 'read', 'update', 'delete']

        properties = CONFIG.sections()

        for property_exp in properties:

            property_dict = {}

            compiled_rule = self._compile_rule(property_exp)

            for operation in operations:

                permissions = CONFIG.get(property_exp, operation)

                if permissions:

                    if self.prop_prot_rule_format == 'policies':

                        if ',' in permissions:

                            LOG.error(

                                _("Multiple policies '%s' not allowed"

                                  "for a given operation. Policies can be "

                                  "combined in the policy file"),

                                permissions)

                            raise InvalidPropProtectConf()

                        self.prop_exp_mapping[compiled_rule] = property_exp

                        self._add_policy_rules(property_exp, operation,

                                               permissions)

                        permissions = [permissions]

                    else:

                        permissions = [permission.strip() for permission in

                                       permissions.split(',')]

                        if '@' in permissions and '!' in permissions:

                            msg = (_(

                                "Malformed property protection rule in "

                                "[%(prop)s] %(op)s=%(perm)s: '@' and '!' "

                                "are mutually exclusive") %

                                dict(prop=property_exp,

                                     op=operation,

                                     perm=permissions))

                            LOG.error(msg)

                            raise InvalidPropProtectConf()

                    property_dict[operation] = permissions

                else:

                    property_dict[operation] = []

                    LOG.warn(

                        _('Property protection on operation %(operation)s'

                          ' for rule %(rule)s is not found. No role will be'

                          ' allowed to perform this operation.') %

                        {'operation': operation,

                         'rule': property_exp})

            self.rules.append((compiled_rule, property_dict))

**** CubicPower OpenStack Study ****

    def _compile_rule(self, rule):

        try:

            return re.compile(rule)

        except Exception as e:

            msg = (_("Encountered a malformed property protection rule"

                     " %(rule)s: %(error)s.") % {'rule': rule,

                                                 'error': e})

            LOG.error(msg)

            raise InvalidPropProtectConf()

**** CubicPower OpenStack Study ****

    def _add_policy_rules(self, property_exp, action, rule):

        """Add policy rules to the policy enforcer.

        For example, if the file listed as property_protection_file has:

        [prop_a]

        create = glance_creator

        then the corresponding policy rule would be:

        "prop_a:create": "rule:glance_creator"

        where glance_creator is defined in policy.json. For example:

        "glance:creator": "role:admin or role:glance_create_user"

        """

        rule = "rule:%s" % rule

        rule_name = "%s:%s" % (property_exp, action)

        rule_dict = {}

        rule_dict[rule_name] = policy.parse_rule(rule)

        self.policy_enforcer.add_rules(rule_dict)

**** CubicPower OpenStack Study ****

    def _check_policy(self, property_exp, action, context):

        try:

            target = ":".join([property_exp, action])

            self.policy_enforcer.enforce(context, target, {})

        except exception.Forbidden:

            return False

        return True

**** CubicPower OpenStack Study ****

    def check_property_rules(self, property_name, action, context):

        roles = context.roles

        if not self.rules:

            return True

        if action not in ['create', 'read', 'update', 'delete']:

            return False

        for rule_exp, rule in self.rules:

            if rule_exp.search(str(property_name)):

                break

        else:  # no matching rules

            return False

        rule_roles = rule.get(action)

        if rule_roles:

            if '!' in rule_roles:

                return False

            elif '@' in rule_roles:

                return True

            if self.prop_prot_rule_format == 'policies':

                prop_exp_key = self.prop_exp_mapping[rule_exp]

                return self._check_policy(prop_exp_key, action,

                                          context)

            if set(roles).intersection(set(rule_roles)):

                return True

        return False