Internet of Things resource management service for OpenStack clouds.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

policy.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. # Copyright (c) 2011 OpenStack Foundation
  2. # All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. """Policy Engine For Ironic."""
  16. import sys
  17. from oslo_concurrency import lockutils
  18. from oslo_config import cfg
  19. from oslo_log import log
  20. from oslo_policy import policy
  21. from iotronic.common import exception
  22. from iotronic.common.i18n import _LW
  23. _ENFORCER = None
  24. CONF = cfg.CONF
  25. LOG = log.getLogger(__name__)
  26. default_policies = [
  27. # Legacy setting, don't remove. Likely to be overridden by operators who
  28. # forget to update their policy.json configuration file.
  29. # This gets rolled into the new "is_admin" rule below.
  30. policy.RuleDefault('admin_api',
  31. 'role:admin or role:administrator',
  32. description='Legacy rule for cloud admin access'),
  33. # is_public_api is set in the environment from AuthTokenMiddleware
  34. policy.RuleDefault('public_api',
  35. 'is_public_api:True',
  36. description='Internal flag for public API routes'),
  37. policy.RuleDefault('is_admin',
  38. 'rule:admin_api',
  39. description='Full read/write API access'),
  40. policy.RuleDefault('is_admin_iot_project',
  41. 'role:admin_iot_project',
  42. description='Full read/write API access'),
  43. policy.RuleDefault('is_manager_iot_project',
  44. 'role:manager_iot_project',
  45. description='Full read/write API access'),
  46. policy.RuleDefault('is_user_iot',
  47. 'role:user_iot',
  48. description='Full read/write API access'),
  49. policy.RuleDefault('is_owner',
  50. 'user:%(owner)s',
  51. description='full access to the owner'),
  52. policy.RuleDefault('admin_or_owner',
  53. 'rule:is_admin or rule:is_owner',
  54. description='full access to the owner or the admin'),
  55. policy.RuleDefault('is_iot_member',
  56. 'rule:is_admin_iot_project '
  57. 'or rule:is_manager_iot_project or rule:is_user_iot',
  58. description='define a member on iot context'),
  59. ]
  60. # NOTE(deva): to follow policy-in-code spec, we define defaults for
  61. # the granular policies in code, rather than in policy.json.
  62. # All of these may be overridden by configuration, but we can
  63. # depend on their existence throughout the code.
  64. board_policies = [
  65. policy.RuleDefault('iot:board:get',
  66. 'rule:is_admin or rule:is_iot_member',
  67. description='Retrieve Board records'),
  68. policy.RuleDefault('iot:board:create',
  69. 'rule:is_admin_iot_project',
  70. description='Create Board records'),
  71. policy.RuleDefault('iot:board:delete',
  72. 'rule:is_admin or rule:is_admin_iot_project '
  73. 'or rule:is_manager_iot_project',
  74. description='Delete Board records'),
  75. policy.RuleDefault('iot:board:update',
  76. 'rule:is_admin or rule:is_admin_iot_project '
  77. 'or rule:is_manager_iot_project',
  78. description='Update Board records'),
  79. ]
  80. plugin_policies = [
  81. policy.RuleDefault('iot:plugin:get',
  82. 'rule:is_admin or rule:is_iot_member',
  83. description='Retrieve Plugin records'),
  84. policy.RuleDefault('iot:plugin:create',
  85. 'rule:is_iot_member',
  86. description='Create Plugin records'),
  87. policy.RuleDefault('iot:plugin:get_one', 'rule:admin_or_owner',
  88. description='Retrieve a Plugin record'),
  89. policy.RuleDefault('iot:plugin:delete', 'rule:admin_or_owner',
  90. description='Delete Plugin records'),
  91. policy.RuleDefault('iot:plugin:update', 'rule:admin_or_owner',
  92. description='Update Plugin records'),
  93. ]
  94. injection_plugin_policies = [
  95. policy.RuleDefault('iot:plugin_on_board:get',
  96. 'rule:admin_or_owner',
  97. description='Retrieve Plugin records'),
  98. policy.RuleDefault('iot:plugin_remove:delete', 'rule:admin_or_owner',
  99. description='Delete Plugin records'),
  100. policy.RuleDefault('iot:plugin_action:post',
  101. 'rule:admin_or_owner',
  102. description='Create Plugin records'),
  103. policy.RuleDefault('iot:plugin_inject:put', 'rule:admin_or_owner',
  104. description='Retrieve a Plugin record'),
  105. ]
  106. service_policies = [
  107. policy.RuleDefault('iot:service:get',
  108. 'rule:is_admin or rule:is_iot_member',
  109. description='Retrieve Service records'),
  110. policy.RuleDefault('iot:service:create',
  111. 'rule:is_iot_member',
  112. description='Create Service records'),
  113. policy.RuleDefault('iot:service:get_one', 'rule:admin_or_owner',
  114. description='Retrieve a Service record'),
  115. policy.RuleDefault('iot:service:delete', 'rule:admin_or_owner',
  116. description='Delete Service records'),
  117. policy.RuleDefault('iot:service:update', 'rule:admin_or_owner',
  118. description='Update Service records'),
  119. ]
  120. exposed_service_policies = [
  121. policy.RuleDefault('iot:service_on_board:get',
  122. 'rule:admin_or_owner',
  123. description='Retrieve Service records'),
  124. policy.RuleDefault('iot:service_remove:delete', 'rule:admin_or_owner',
  125. description='Delete Service records'),
  126. policy.RuleDefault('iot:service_action:post',
  127. 'rule:admin_or_owner',
  128. description='Create Service records'),
  129. policy.RuleDefault('iot:service_inject:put', 'rule:admin_or_owner',
  130. description='Retrieve a Service record'),
  131. ]
  132. def list_policies():
  133. policies = (default_policies
  134. + board_policies
  135. + plugin_policies
  136. + injection_plugin_policies
  137. + service_policies
  138. + exposed_service_policies
  139. )
  140. return policies
  141. @lockutils.synchronized('policy_enforcer')
  142. def init_enforcer(policy_file=None, rules=None,
  143. default_rule=None, use_conf=True):
  144. """Synchronously initializes the policy enforcer
  145. :param policy_file: Custom policy file to use, if none is specified,
  146. `CONF.oslo_policy.policy_file` will be used.
  147. :param rules: Default dictionary / Rules to use. It will be
  148. considered just in the first instantiation.
  149. :param default_rule: Default rule to use,
  150. CONF.oslo_policy.policy_default_rule will
  151. be used if none is specified.
  152. :param use_conf: Whether to load rules from config file.
  153. """
  154. global _ENFORCER
  155. if _ENFORCER:
  156. return
  157. # NOTE(deva): Register defaults for policy-in-code here so that they are
  158. # loaded exactly once - when this module-global is initialized.
  159. # Defining these in the relevant API modules won't work
  160. # because API classes lack singletons and don't use globals.
  161. _ENFORCER = policy.Enforcer(CONF, policy_file=policy_file,
  162. rules=rules,
  163. default_rule=default_rule,
  164. use_conf=use_conf)
  165. _ENFORCER.register_defaults(list_policies())
  166. def get_enforcer():
  167. """Provides access to the single instance of Policy enforcer."""
  168. if not _ENFORCER:
  169. init_enforcer()
  170. return _ENFORCER
  171. def get_oslo_policy_enforcer():
  172. # This method is for use by oslopolicy CLI scripts. Those scripts need the
  173. # 'output-file' and 'namespace' options, but having those in sys.argv means
  174. # loading the Ironic config options will fail as those are not expected to
  175. # be present. So we pass in an arg list with those stripped out.
  176. conf_args = []
  177. # Start at 1 because cfg.CONF expects the equivalent of sys.argv[1:]
  178. i = 1
  179. while i < len(sys.argv):
  180. if sys.argv[i].strip('-') in ['namespace', 'output-file']:
  181. i += 2
  182. continue
  183. conf_args.append(sys.argv[i])
  184. i += 1
  185. cfg.CONF(conf_args, project='ironic')
  186. return get_enforcer()
  187. # NOTE(deva): We can't call these methods from within decorators because the
  188. # 'target' and 'creds' parameter must be fetched from the call time
  189. # context-local pecan.request magic variable, but decorators are compiled
  190. # at module-load time.
  191. def authorize(rule, target, creds, *args, **kwargs):
  192. """A shortcut for policy.Enforcer.authorize()
  193. Checks authorization of a rule against the target and credentials, and
  194. raises an exception if the rule is not defined.
  195. Always returns true if CONF.auth_strategy == noauth.
  196. Beginning with the Newton cycle, this should be used in place of 'enforce'.
  197. """
  198. if CONF.auth_strategy == 'noauth':
  199. return True
  200. enforcer = get_enforcer()
  201. try:
  202. return enforcer.authorize(rule, target, creds, do_raise=True,
  203. *args, **kwargs)
  204. except policy.PolicyNotAuthorized:
  205. raise exception.HTTPForbidden(resource=rule)
  206. def check(rule, target, creds, *args, **kwargs):
  207. """A shortcut for policy.Enforcer.enforce()
  208. Checks authorization of a rule against the target and credentials
  209. and returns True or False.
  210. """
  211. enforcer = get_enforcer()
  212. return enforcer.enforce(rule, target, creds, *args, **kwargs)
  213. def enforce(rule, target, creds, do_raise=False, exc=None, *args, **kwargs):
  214. """A shortcut for policy.Enforcer.enforce()
  215. Checks authorization of a rule against the target and credentials.
  216. Always returns true if CONF.auth_strategy == noauth.
  217. """
  218. # NOTE(deva): this method is obsoleted by authorize(), but retained for
  219. # backwards compatibility in case it has been used downstream.
  220. # It may be removed in the Pike cycle.
  221. LOG.warning(_LW(
  222. "Deprecation warning: calls to ironic.common.policy.enforce() "
  223. "should be replaced with authorize(). This method may be removed "
  224. "in a future release."))
  225. if CONF.auth_strategy == 'noauth':
  226. return True
  227. enforcer = get_enforcer()
  228. return enforcer.enforce(rule, target, creds, do_raise=do_raise,
  229. exc=exc, *args, **kwargs)