1# Copyright 2011 OpenStack Foundation 2# Copyright 2011 Nebula, Inc. 3# All Rights Reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# not use this file except in compliance with the License. You may obtain 7# a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations 15# under the License. 16 17from debtcollector import removals 18 19from keystoneclient import base 20from keystoneclient import exceptions 21from keystoneclient.i18n import _ 22 23 24class Role(base.Resource): 25 """Represents an Identity role. 26 27 Attributes: 28 * id: a uuid that identifies the role 29 * name: user-facing identifier 30 * domain: optional domain for the role 31 32 """ 33 34 pass 35 36 37class InferenceRule(base.Resource): 38 """Represents a rule that states one role implies another. 39 40 Attributes: 41 * prior_role: this role implies the other 42 * implied_role: this role is implied by the other 43 44 """ 45 46 pass 47 48 49class RoleManager(base.CrudManager): 50 """Manager class for manipulating Identity roles.""" 51 52 resource_class = Role 53 collection_key = 'roles' 54 key = 'role' 55 deprecation_msg = 'keystoneclient.v3.roles.InferenceRuleManager' 56 57 def _role_grants_base_url(self, user, group, system, domain, project, 58 use_inherit_extension): 59 # When called, we have already checked that only one of user & group 60 # and one of domain & project have been specified 61 params = {} 62 63 if project: 64 params['project_id'] = base.getid(project) 65 base_url = '/projects/%(project_id)s' 66 elif domain: 67 params['domain_id'] = base.getid(domain) 68 base_url = '/domains/%(domain_id)s' 69 elif system: 70 if system == 'all': 71 base_url = '/system' 72 else: 73 # NOTE(lbragstad): If we've made it this far, a user is 74 # attempting to do something with system scope that isn't 75 # supported yet (e.g. 'all' is currently the only supported 76 # system scope). In the future that may change but until then 77 # we should fail like we would if a user provided a bogus 78 # project name or domain ID. 79 msg = _("Only a system scope of 'all' is currently supported") 80 raise exceptions.ValidationError(msg) 81 82 if use_inherit_extension: 83 base_url = '/OS-INHERIT' + base_url 84 85 if user: 86 params['user_id'] = base.getid(user) 87 base_url += '/users/%(user_id)s' 88 elif group: 89 params['group_id'] = base.getid(group) 90 base_url += '/groups/%(group_id)s' 91 92 return base_url % params 93 94 def _enforce_mutually_exclusive_group(self, system, domain, project): 95 if not system: 96 if domain and project: 97 msg = _('Specify either a domain or project, not both') 98 raise exceptions.ValidationError(msg) 99 elif not (domain or project): 100 msg = _('Must specify either system, domain, or project') 101 raise exceptions.ValidationError(msg) 102 elif system: 103 if domain and project: 104 msg = _( 105 'Specify either system, domain, or project, not all three.' 106 ) 107 raise exceptions.ValidationError(msg) 108 if domain: 109 msg = _('Specify either system or a domain, not both') 110 raise exceptions.ValidationError(msg) 111 if project: 112 msg = _('Specify either a system or project, not both') 113 raise exceptions.ValidationError(msg) 114 115 def _require_user_xor_group(self, user, group): 116 if user and group: 117 msg = _('Specify either a user or group, not both') 118 raise exceptions.ValidationError(msg) 119 elif not (user or group): 120 msg = _('Must specify either a user or group') 121 raise exceptions.ValidationError(msg) 122 123 def create(self, name, domain=None, **kwargs): 124 """Create a role. 125 126 :param str name: the name of the role. 127 :param domain: the domain of the role. If a value is passed it is a 128 domain-scoped role, otherwise it's a global role. 129 :type domain: str or :class:`keystoneclient.v3.domains.Domain` 130 :param kwargs: any other attribute provided will be passed to the 131 server. 132 133 :returns: the created role returned from server. 134 :rtype: :class:`keystoneclient.v3.roles.Role` 135 136 """ 137 domain_id = None 138 if domain: 139 domain_id = base.getid(domain) 140 141 return super(RoleManager, self).create( 142 name=name, 143 domain_id=domain_id, 144 **kwargs) 145 146 def get(self, role): 147 """Retrieve a role. 148 149 :param role: the role to be retrieved from the server. 150 :type role: str or :class:`keystoneclient.v3.roles.Role` 151 152 :returns: the specified role returned from server. 153 :rtype: :class:`keystoneclient.v3.roles.Role` 154 155 """ 156 return super(RoleManager, self).get(role_id=base.getid(role)) 157 158 def list(self, user=None, group=None, system=None, domain=None, 159 project=None, os_inherit_extension_inherited=False, **kwargs): 160 """List roles and role grants. 161 162 :param user: filter in role grants for the specified user on a 163 resource. Domain or project must be specified. 164 User and group are mutually exclusive. 165 :type user: str or :class:`keystoneclient.v3.users.User` 166 :param group: filter in role grants for the specified group on a 167 resource. Domain or project must be specified. 168 User and group are mutually exclusive. 169 :type group: str or :class:`keystoneclient.v3.groups.Group` 170 :param domain: filter in role grants on the specified domain. Either 171 user or group must be specified. Project, domain, and 172 system are mutually exclusive. 173 :type domain: str or :class:`keystoneclient.v3.domains.Domain` 174 :param project: filter in role grants on the specified project. Either 175 user or group must be specified. Project, domain and 176 system are mutually exclusive. 177 :type project: str or :class:`keystoneclient.v3.projects.Project` 178 :param bool os_inherit_extension_inherited: OS-INHERIT will be used. 179 It provides the ability for 180 projects to inherit role 181 assignments from their 182 domains or from parent 183 projects in the hierarchy. 184 :param kwargs: any other attribute provided will filter roles on. 185 186 :returns: a list of roles. 187 :rtype: list of :class:`keystoneclient.v3.roles.Role` 188 189 """ 190 if os_inherit_extension_inherited: 191 kwargs['tail'] = '/inherited_to_projects' 192 if user or group: 193 self._require_user_xor_group(user, group) 194 self._enforce_mutually_exclusive_group(system, domain, project) 195 196 base_url = self._role_grants_base_url( 197 user, group, system, domain, project, 198 os_inherit_extension_inherited 199 ) 200 return super(RoleManager, self).list(base_url=base_url, 201 **kwargs) 202 203 return super(RoleManager, self).list(**kwargs) 204 205 def update(self, role, name=None, **kwargs): 206 """Update a role. 207 208 :param role: the role to be updated on the server. 209 :type role: str or :class:`keystoneclient.v3.roles.Role` 210 :param str name: the new name of the role. 211 :param kwargs: any other attribute provided will be passed to server. 212 213 :returns: the updated role returned from server. 214 :rtype: :class:`keystoneclient.v3.roles.Role` 215 216 """ 217 return super(RoleManager, self).update( 218 role_id=base.getid(role), 219 name=name, 220 **kwargs) 221 222 def delete(self, role): 223 """Delete a role. 224 225 When a role is deleted all the role inferences that have deleted role 226 as prior role will be deleted as well. 227 228 :param role: the role to be deleted on the server. 229 :type role: str or :class:`keystoneclient.v3.roles.Role` 230 231 :returns: Response object with 204 status. 232 :rtype: :class:`requests.models.Response` 233 234 """ 235 return super(RoleManager, self).delete( 236 role_id=base.getid(role)) 237 238 def grant(self, role, user=None, group=None, system=None, domain=None, 239 project=None, os_inherit_extension_inherited=False, **kwargs): 240 """Grant a role to a user or group on a domain or project. 241 242 :param role: the role to be granted on the server. 243 :type role: str or :class:`keystoneclient.v3.roles.Role` 244 :param user: the specified user to have the role granted on a resource. 245 Domain or project must be specified. User and group are 246 mutually exclusive. 247 :type user: str or :class:`keystoneclient.v3.users.User` 248 :param group: the specified group to have the role granted on a 249 resource. Domain or project must be specified. 250 User and group are mutually exclusive. 251 :type group: str or :class:`keystoneclient.v3.groups.Group` 252 :param system: system information to grant the role on. Project, 253 domain, and system are mutually exclusive. 254 :type system: str 255 :param domain: the domain in which the role will be granted. Either 256 user or group must be specified. Project, domain, and 257 system are mutually exclusive. 258 :type domain: str or :class:`keystoneclient.v3.domains.Domain` 259 :param project: the project in which the role will be granted. Either 260 user or group must be specified. Project, domain, and 261 system are mutually exclusive. 262 :type project: str or :class:`keystoneclient.v3.projects.Project` 263 :param bool os_inherit_extension_inherited: OS-INHERIT will be used. 264 It provides the ability for 265 projects to inherit role 266 assignments from their 267 domains or from parent 268 projects in the hierarchy. 269 :param kwargs: any other attribute provided will be passed to server. 270 271 :returns: the granted role returned from server. 272 :rtype: :class:`keystoneclient.v3.roles.Role` 273 274 """ 275 self._enforce_mutually_exclusive_group(system, domain, project) 276 self._require_user_xor_group(user, group) 277 278 if os_inherit_extension_inherited: 279 kwargs['tail'] = '/inherited_to_projects' 280 281 base_url = self._role_grants_base_url( 282 user, group, system, domain, project, 283 os_inherit_extension_inherited) 284 return super(RoleManager, self).put(base_url=base_url, 285 role_id=base.getid(role), 286 **kwargs) 287 288 def check(self, role, user=None, group=None, system=None, domain=None, 289 project=None, os_inherit_extension_inherited=False, **kwargs): 290 """Check if a user or group has a role on a domain or project. 291 292 :param user: check for role grants for the specified user on a 293 resource. Domain or project must be specified. 294 User and group are mutually exclusive. 295 :type user: str or :class:`keystoneclient.v3.users.User` 296 :param group: check for role grants for the specified group on a 297 resource. Domain or project must be specified. 298 User and group are mutually exclusive. 299 :type group: str or :class:`keystoneclient.v3.groups.Group` 300 :param system: check for role grants on the system. Project, domain, 301 and system are mutually exclusive. 302 :type system: str 303 :param domain: check for role grants on the specified domain. Either 304 user or group must be specified. Project, domain, and 305 system are mutually exclusive. 306 :type domain: str or :class:`keystoneclient.v3.domains.Domain` 307 :param project: check for role grants on the specified project. Either 308 user or group must be specified. Project, domain, and 309 system are mutually exclusive. 310 :type project: str or :class:`keystoneclient.v3.projects.Project` 311 :param bool os_inherit_extension_inherited: OS-INHERIT will be used. 312 It provides the ability for 313 projects to inherit role 314 assignments from their 315 domains or from parent 316 projects in the hierarchy. 317 :param kwargs: any other attribute provided will be passed to server. 318 319 :returns: the specified role returned from server if it exists. 320 :rtype: :class:`keystoneclient.v3.roles.Role` 321 322 :returns: Response object with 204 status if specified role 323 doesn't exist. 324 :rtype: :class:`requests.models.Response` 325 326 """ 327 self._enforce_mutually_exclusive_group(system, domain, project) 328 self._require_user_xor_group(user, group) 329 330 if os_inherit_extension_inherited: 331 kwargs['tail'] = '/inherited_to_projects' 332 333 base_url = self._role_grants_base_url( 334 user, group, system, domain, project, 335 os_inherit_extension_inherited) 336 return super(RoleManager, self).head( 337 base_url=base_url, 338 role_id=base.getid(role), 339 os_inherit_extension_inherited=os_inherit_extension_inherited, 340 **kwargs) 341 342 def revoke(self, role, user=None, group=None, system=None, domain=None, 343 project=None, os_inherit_extension_inherited=False, **kwargs): 344 """Revoke a role from a user or group on a domain or project. 345 346 :param user: revoke role grants for the specified user on a 347 resource. Domain or project must be specified. 348 User and group are mutually exclusive. 349 :type user: str or :class:`keystoneclient.v3.users.User` 350 :param group: revoke role grants for the specified group on a 351 resource. Domain or project must be specified. 352 User and group are mutually exclusive. 353 :type group: str or :class:`keystoneclient.v3.groups.Group` 354 :param system: revoke role grants on the system. Project, domain, and 355 system are mutually exclusive. 356 :type system: str 357 :param domain: revoke role grants on the specified domain. Either 358 user or group must be specified. Project, domain, and 359 system are mutually exclusive. 360 :type domain: str or :class:`keystoneclient.v3.domains.Domain` 361 :param project: revoke role grants on the specified project. Either 362 user or group must be specified. Project, domain, and 363 system are mutually exclusive. 364 :type project: str or :class:`keystoneclient.v3.projects.Project` 365 :param bool os_inherit_extension_inherited: OS-INHERIT will be used. 366 It provides the ability for 367 projects to inherit role 368 assignments from their 369 domains or from parent 370 projects in the hierarchy. 371 :param kwargs: any other attribute provided will be passed to server. 372 373 :returns: the revoked role returned from server. 374 :rtype: list of :class:`keystoneclient.v3.roles.Role` 375 376 """ 377 self._enforce_mutually_exclusive_group(system, domain, project) 378 self._require_user_xor_group(user, group) 379 380 if os_inherit_extension_inherited: 381 kwargs['tail'] = '/inherited_to_projects' 382 383 base_url = self._role_grants_base_url( 384 user, group, system, domain, project, 385 os_inherit_extension_inherited) 386 return super(RoleManager, self).delete( 387 base_url=base_url, 388 role_id=base.getid(role), 389 os_inherit_extension_inherited=os_inherit_extension_inherited, 390 **kwargs) 391 392 @removals.remove(message='Use %s.create instead.' % deprecation_msg, 393 version='3.9.0', removal_version='4.0.0') 394 def create_implied(self, prior_role, implied_role, **kwargs): 395 return InferenceRuleManager(self.client).create(prior_role, 396 implied_role) 397 398 @removals.remove(message='Use %s.delete instead.' % deprecation_msg, 399 version='3.9.0', removal_version='4.0.0') 400 def delete_implied(self, prior_role, implied_role, **kwargs): 401 return InferenceRuleManager(self.client).delete(prior_role, 402 implied_role) 403 404 @removals.remove(message='Use %s.get instead.' % deprecation_msg, 405 version='3.9.0', removal_version='4.0.0') 406 def get_implied(self, prior_role, implied_role, **kwargs): 407 return InferenceRuleManager(self.client).get(prior_role, 408 implied_role) 409 410 @removals.remove(message='Use %s.check instead.' % deprecation_msg, 411 version='3.9.0', removal_version='4.0.0') 412 def check_implied(self, prior_role, implied_role, **kwargs): 413 return InferenceRuleManager(self.client).check(prior_role, 414 implied_role) 415 416 @removals.remove(message='Use %s.list_inference_roles' % deprecation_msg, 417 version='3.9.0', removal_version='4.0.0') 418 def list_role_inferences(self, **kwargs): 419 return InferenceRuleManager(self.client).list_inference_roles() 420 421 422class InferenceRuleManager(base.CrudManager): 423 """Manager class for manipulating Identity inference rules.""" 424 425 resource_class = InferenceRule 426 collection_key = 'role_inferences' 427 key = 'role_inference' 428 429 def _implied_role_url_tail(self, prior_role, implied_role): 430 base_url = ('/%(prior_role_id)s/implies/%(implied_role_id)s' % 431 {'prior_role_id': base.getid(prior_role), 432 'implied_role_id': base.getid(implied_role)}) 433 return base_url 434 435 def create(self, prior_role, implied_role): 436 """Create an inference rule. 437 438 An inference rule is comprised of two roles, a prior role and an 439 implied role. The prior role will imply the implied role. 440 441 Valid HTTP return codes: 442 443 * 201: Resource is created successfully 444 * 404: A role cannot be found 445 * 409: The inference rule already exists 446 447 :param prior_role: the role which implies ``implied_role``. 448 :type role: str or :class:`keystoneclient.v3.roles.Role` 449 :param implied_role: the role which is implied by ``prior_role``. 450 :type role: str or :class:`keystoneclient.v3.roles.Role` 451 452 :returns: a newly created role inference returned from server. 453 :rtype: :class:`keystoneclient.v3.roles.InferenceRule` 454 455 """ 456 url_tail = self._implied_role_url_tail(prior_role, implied_role) 457 _resp, body = self.client.put("/roles" + url_tail) 458 return self._prepare_return_value( 459 _resp, self.resource_class(self, body['role_inference'])) 460 461 def delete(self, prior_role, implied_role): 462 """Delete an inference rule. 463 464 When deleting an inference rule, both roles are required. Note that 465 neither role is deleted, only the inference relationship is dissolved. 466 467 Valid HTTP return codes: 468 469 * 204: Delete request is accepted 470 * 404: A role cannot be found 471 472 :param prior_role: the role which implies ``implied_role``. 473 :type role: str or :class:`keystoneclient.v3.roles.Role` 474 :param implied_role: the role which is implied by ``prior_role``. 475 :type role: str or :class:`keystoneclient.v3.roles.Role` 476 477 :returns: Response object with 204 status. 478 :rtype: :class:`requests.models.Response` 479 480 """ 481 url_tail = self._implied_role_url_tail(prior_role, implied_role) 482 return self._delete("/roles" + url_tail) 483 484 def get(self, prior_role, implied_role): 485 """Retrieve an inference rule. 486 487 Valid HTTP return codes: 488 489 * 200: Inference rule is returned 490 * 404: A role cannot be found 491 492 :param prior_role: the role which implies ``implied_role``. 493 :type role: str or :class:`keystoneclient.v3.roles.Role` 494 :param implied_role: the role which is implied by ``prior_role``. 495 :type role: str or :class:`keystoneclient.v3.roles.Role` 496 497 :returns: the specified role inference returned from server. 498 :rtype: :class:`keystoneclient.v3.roles.InferenceRule` 499 500 """ 501 url_tail = self._implied_role_url_tail(prior_role, implied_role) 502 _resp, body = self.client.get("/roles" + url_tail) 503 return self._prepare_return_value( 504 _resp, self.resource_class(self, body['role_inference'])) 505 506 def list(self, prior_role): 507 """List all roles that a role may imply. 508 509 Valid HTTP return codes: 510 511 * 200: List of inference rules are returned 512 * 404: A role cannot be found 513 514 :param prior_role: the role which implies ``implied_role``. 515 :type role: str or :class:`keystoneclient.v3.roles.Role` 516 517 :returns: the specified role inference returned from server. 518 :rtype: :class:`keystoneclient.v3.roles.InferenceRule` 519 520 """ 521 url_tail = ('/%s/implies' % base.getid(prior_role)) 522 _resp, body = self.client.get("/roles" + url_tail) 523 return self._prepare_return_value( 524 _resp, self.resource_class(self, body['role_inference'])) 525 526 def check(self, prior_role, implied_role): 527 """Check if an inference rule exists. 528 529 Valid HTTP return codes: 530 531 * 204: The rule inference exists 532 * 404: A role cannot be found 533 534 :param prior_role: the role which implies ``implied_role``. 535 :type role: str or :class:`keystoneclient.v3.roles.Role` 536 :param implied_role: the role which is implied by ``prior_role``. 537 :type role: str or :class:`keystoneclient.v3.roles.Role` 538 539 :returns: response object with 204 status returned from server. 540 :rtype: :class:`requests.models.Response` 541 542 """ 543 url_tail = self._implied_role_url_tail(prior_role, implied_role) 544 return self._head("/roles" + url_tail) 545 546 def list_inference_roles(self): 547 """List all rule inferences. 548 549 Valid HTTP return codes: 550 551 * 200: All inference rules are returned 552 553 :param kwargs: attributes provided will be passed to the server. 554 555 :returns: a list of inference rules. 556 :rtype: list of :class:`keystoneclient.v3.roles.InferenceRule` 557 558 """ 559 return super(InferenceRuleManager, self).list() 560 561 def update(self, **kwargs): 562 raise exceptions.MethodNotImplemented( 563 _('Update not supported for rule inferences')) 564 565 def find(self, **kwargs): 566 raise exceptions.MethodNotImplemented( 567 _('Find not supported for rule inferences')) 568 569 def put(self, **kwargs): 570 raise exceptions.MethodNotImplemented( 571 _('Put not supported for rule inferences')) 572