auth.py 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # -*- coding: utf-8 -*-
  2. import typing
  3. from json.decoder import JSONDecodeError
  4. from sqlalchemy.orm.exc import NoResultFound
  5. from pyramid.request import Request
  6. from pyramid.security import ALL_PERMISSIONS
  7. from pyramid.security import Allow
  8. from pyramid.security import unauthenticated_userid
  9. from tracim.models.auth import Group
  10. from tracim.models.auth import User
  11. from tracim.models.data import Workspace
  12. from tracim.models.data import UserRoleInWorkspace
  13. from tracim.lib.core.user import UserApi
  14. from tracim.lib.core.workspace import WorkspaceApi
  15. from tracim.lib.core.userworkspace import RoleApi
  16. # INFO - G.M - 06-04-2018 - Auth for pyramid
  17. # based on this tutorial : https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/auth/basic.html # nopep8
  18. BASIC_AUTH_WEBUI_REALM = "tracim"
  19. def get_user(request: Request) -> typing.Optional[User]:
  20. """
  21. Get current pyramid user from request
  22. :param request: pyramid request
  23. :return:
  24. """
  25. app_config = request.registry.settings['CFG']
  26. uapi = UserApi(None, session=request.dbsession, config=app_config)
  27. user = None
  28. try:
  29. login = unauthenticated_userid(request)
  30. user = uapi.get_one_by_email(login)
  31. except NoResultFound:
  32. pass
  33. return user
  34. def get_workspace(request: Request) -> typing.Optional[Workspace]:
  35. """
  36. Get current workspace from request
  37. :param request: pyramid request
  38. :return:
  39. """
  40. workspace = None
  41. try:
  42. if 'workspace_id' not in request.json_body:
  43. return None
  44. workspace_id = request.json_body['workspace_id']
  45. wapi = WorkspaceApi(current_user=None, session=request.dbsession)
  46. workspace = wapi.get_one(workspace_id)
  47. except JSONDecodeError:
  48. pass
  49. except NoResultFound:
  50. pass
  51. return workspace
  52. def check_credentials(
  53. login: str,
  54. cleartext_password: str,
  55. request: Request
  56. ) -> typing.Optional[list]:
  57. """
  58. Check credential for pyramid basic_auth, checks also for
  59. global and Workspace related permissions.
  60. :param login: login of user
  61. :param cleartext_password: user password in cleartext
  62. :param request: Pyramid request
  63. :return: None if auth failed, list of permissions if auth succeed
  64. """
  65. user = get_user(request)
  66. # Do not accept invalid user
  67. if not user \
  68. or user.email != login \
  69. or not user.validate_password(cleartext_password):
  70. return None
  71. permissions = []
  72. # Global groups
  73. for group in user.groups:
  74. permissions.append(group.group_id)
  75. # Current workspace related group
  76. workspace = get_workspace(request)
  77. if workspace:
  78. roleapi = RoleApi(current_user=user, session=request.dbsession)
  79. role = roleapi.get_one(
  80. user_id=user.user_id,
  81. workspace_id=workspace.workspace_id,
  82. )
  83. permissions.append(role)
  84. return permissions
  85. # Global Permissions
  86. ADMIN_PERM = 'admin'
  87. MANAGE_GLOBAL_PERM = 'manage_global'
  88. USER_PERM = 'user'
  89. # Workspace-specific permission
  90. READ_PERM = 'read'
  91. CONTRIBUTE_PERM = 'contribute'
  92. MANAGE_CONTENT_PERM = 'manage_content'
  93. MANAGE_WORKSPACE_PERM = 'manage_workspace'
  94. class Root(object):
  95. """
  96. Root of all Pyramid requests, used to store global acl
  97. """
  98. __acl__ = ()