auth.py 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # -*- coding: utf-8 -*-
  2. import typing
  3. from pyramid.interfaces import IAuthorizationPolicy
  4. from zope.interface import implementer
  5. try:
  6. from json.decoder import JSONDecodeError
  7. except ImportError: # python3.4
  8. JSONDecodeError = ValueError
  9. from sqlalchemy.orm.exc import NoResultFound
  10. from pyramid.request import Request
  11. from tracim.models.auth import User
  12. from tracim.models.data import Workspace
  13. from tracim.lib.core.user import UserApi
  14. from tracim.lib.core.workspace import WorkspaceApi
  15. from tracim.exceptions import NotAuthentificated
  16. from tracim.exceptions import WorkspaceNotFound
  17. from tracim.exceptions import InsufficientUserWorkspaceRole
  18. BASIC_AUTH_WEBUI_REALM = "tracim"
  19. TRACIM_DEFAULT_PERM = 'tracim'
  20. def get_safe_user(
  21. request: Request,
  22. ) -> User:
  23. """
  24. Get current pyramid authenticated user from request
  25. :param request: pyramid request
  26. :return: current authenticated user
  27. """
  28. app_config = request.registry.settings['CFG']
  29. uapi = UserApi(None, session=request.dbsession, config=app_config)
  30. user = None
  31. try:
  32. login = request.authenticated_userid
  33. if not login:
  34. raise NotAuthentificated('not authenticated user_id,'
  35. 'Failed Authentification ?')
  36. user = uapi.get_one_by_email(login)
  37. except NoResultFound:
  38. raise NotAuthentificated('User not found')
  39. return user
  40. def get_workspace(user: User, request: Request) -> typing.Optional[Workspace]:
  41. """
  42. Get current workspace from request
  43. :param user: User who want to check the workspace
  44. :param request: pyramid request
  45. :return:
  46. """
  47. workspace_id = ''
  48. try:
  49. if 'workspace_id' not in request.json_body:
  50. return None
  51. workspace_id = request.json_body['workspace_id']
  52. wapi = WorkspaceApi(current_user=user, session=request.dbsession)
  53. workspace = wapi.get_one(workspace_id)
  54. except JSONDecodeError:
  55. raise WorkspaceNotFound('Bad json body')
  56. except NoResultFound:
  57. raise WorkspaceNotFound(
  58. 'Workspace {} does not exist '
  59. 'or is not visible for this user'.format(workspace_id)
  60. )
  61. return workspace
  62. ###
  63. # BASIC AUTH
  64. ###
  65. def basic_auth_check_credentials(
  66. login: str,
  67. cleartext_password: str,
  68. request: 'TracimRequest'
  69. ) -> typing.Optional[list]:
  70. """
  71. Check credential for pyramid basic_auth
  72. :param login: login of user
  73. :param cleartext_password: user password in cleartext
  74. :param request: Pyramid request
  75. :return: None if auth failed, list of permissions if auth succeed
  76. """
  77. # Do not accept invalid user
  78. user = _get_basic_auth_unsafe_user(request)
  79. if not user \
  80. or user.email != login \
  81. or not user.validate_password(cleartext_password):
  82. return None
  83. return []
  84. def _get_basic_auth_unsafe_user(
  85. request: Request,
  86. ) -> typing.Optional[User]:
  87. """
  88. :param request: pyramid request
  89. :return: User or None
  90. """
  91. app_config = request.registry.settings['CFG']
  92. uapi = UserApi(None, session=request.dbsession, config=app_config)
  93. try:
  94. login = request.unauthenticated_userid
  95. if not login:
  96. return None
  97. user = uapi.get_one_by_email(login)
  98. except NoResultFound:
  99. return None
  100. return user
  101. ####
  102. def require_workspace_role(minimal_required_role):
  103. def decorator(func):
  104. def wrapper(self, request: 'TracimRequest'):
  105. user = request.current_user
  106. workspace = request.current_workspace
  107. if workspace.get_user_role(user) >= minimal_required_role:
  108. return func(self, request)
  109. raise InsufficientUserWorkspaceRole()
  110. return wrapper
  111. return decorator
  112. ###
  113. @implementer(IAuthorizationPolicy)
  114. class AcceptAllAuthorizationPolicy(object):
  115. """
  116. Simple AuthorizationPolicy to avoid trouble with pyramid.
  117. Acceot any request.
  118. """
  119. def permits(self, context, principals, permision):
  120. return True
  121. def principals_allowed_by_permission(self, context, permission):
  122. raise NotImplementedError()