authorization.py 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. # -*- coding: utf-8 -*-
  2. import typing
  3. from typing import TYPE_CHECKING
  4. import functools
  5. from pyramid.interfaces import IAuthorizationPolicy
  6. from zope.interface import implementer
  7. from tracim.models.contents import NewContentType
  8. try:
  9. from json.decoder import JSONDecodeError
  10. except ImportError: # python3.4
  11. JSONDecodeError = ValueError
  12. from tracim.exceptions import InsufficientUserWorkspaceRole
  13. from tracim.exceptions import ContentTypeNotAllowed
  14. from tracim.exceptions import InsufficientUserProfile
  15. if TYPE_CHECKING:
  16. from tracim import TracimRequest
  17. ###
  18. # Pyramid default permission/authorization mecanism
  19. # INFO - G.M - 12-04-2018 - Setiing a Default permission on view is
  20. # needed to activate AuthentificationPolicy and
  21. # AuthorizationPolicy on pyramid request
  22. TRACIM_DEFAULT_PERM = 'tracim'
  23. @implementer(IAuthorizationPolicy)
  24. class AcceptAllAuthorizationPolicy(object):
  25. """
  26. Empty AuthorizationPolicy : Allow all request. As Pyramid need
  27. a Authorization policy when we use AuthentificationPolicy, this
  28. class permit use to disable pyramid authorization mecanism with
  29. working a AuthentificationPolicy.
  30. """
  31. def permits(self, context, principals, permision):
  32. return True
  33. def principals_allowed_by_permission(self, context, permission):
  34. raise NotImplementedError()
  35. ###
  36. # Authorization decorators for views
  37. # INFO - G.M - 12-04-2018
  38. # Instead of relying on pyramid authorization mecanism
  39. # We prefer to use decorators
  40. def require_same_user_or_profile(group: int):
  41. """
  42. Decorator for view to restrict access of tracim request if candidate user
  43. is distinct from authenticated user and not with high enough profile.
  44. :param group: value from Group Object
  45. like Group.TIM_USER or Group.TIM_MANAGER
  46. :return:
  47. """
  48. def decorator(func):
  49. def wrapper(self, context, request: 'TracimRequest'):
  50. auth_user = request.current_user
  51. candidate_user = request.candidate_user
  52. if auth_user.user_id == candidate_user.user_id or \
  53. auth_user.profile.id >= group:
  54. return func(self, context, request)
  55. raise InsufficientUserProfile()
  56. return wrapper
  57. return decorator
  58. def require_profile(group: int):
  59. """
  60. Decorator for view to restrict access of tracim request if profile is
  61. not high enough
  62. :param group: value from Group Object
  63. like Group.TIM_USER or Group.TIM_MANAGER
  64. :return:
  65. """
  66. def decorator(func):
  67. def wrapper(self, context, request: 'TracimRequest'):
  68. user = request.current_user
  69. if user.profile.id >= group:
  70. return func(self, context, request)
  71. raise InsufficientUserProfile()
  72. return wrapper
  73. return decorator
  74. def require_workspace_role(minimal_required_role: int):
  75. """
  76. Restricts access to endpoint to minimal role or raise an exception.
  77. Check role for current_workspace.
  78. :param minimal_required_role: value from UserInWorkspace Object like
  79. UserRoleInWorkspace.CONTRIBUTOR or UserRoleInWorkspace.READER
  80. :return: decorator
  81. """
  82. def decorator(func):
  83. def wrapper(self, context, request: 'TracimRequest'):
  84. user = request.current_user
  85. workspace = request.current_workspace
  86. if workspace.get_user_role(user) >= minimal_required_role:
  87. return func(self, context, request)
  88. raise InsufficientUserWorkspaceRole()
  89. return wrapper
  90. return decorator
  91. def require_candidate_workspace_role(minimal_required_role: int):
  92. """
  93. Restricts access to endpoint to minimal role or raise an exception.
  94. Check role for candidate_workspace.
  95. :param minimal_required_role: value from UserInWorkspace Object like
  96. UserRoleInWorkspace.CONTRIBUTOR or UserRoleInWorkspace.READER
  97. :return: decorator
  98. """
  99. def decorator(func):
  100. def wrapper(self, context, request: 'TracimRequest'):
  101. user = request.current_user
  102. workspace = request.candidate_workspace
  103. if workspace.get_user_role(user) >= minimal_required_role:
  104. return func(self, context, request)
  105. raise InsufficientUserWorkspaceRole()
  106. return wrapper
  107. return decorator
  108. def require_content_types(content_types: typing.List['NewContentType']):
  109. """
  110. Restricts access to specific file type or raise an exception.
  111. Check role for candidate_workspace.
  112. :param content_types: list of NewContentType object
  113. :return: decorator
  114. """
  115. def decorator(func):
  116. @functools.wraps(func)
  117. def wrapper(self, context, request: 'TracimRequest'):
  118. content = request.current_content
  119. if content.type in [content.slug for content in content_types]:
  120. return func(self, context, request)
  121. raise ContentTypeNotAllowed()
  122. return wrapper
  123. return decorator