permissions.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from ipaddress import IPv4Address, IPv4Network
  2. from rest_framework import permissions
  3. class IsActiveUser(permissions.BasePermission):
  4. """
  5. Allows access only to activated users.
  6. """
  7. def has_permission(self, request, view):
  8. # Authenticated users can have is_active = None (pending activation). Those are not considered active.
  9. return request.user and request.user.is_active
  10. class IsAPIToken(permissions.BasePermission):
  11. """
  12. Allows access only with API token (.mfa is None).
  13. """
  14. message = "API token required."
  15. code = "api_token_required"
  16. def has_permission(self, request, view):
  17. return request.auth.mfa is None
  18. class IsLoginToken(permissions.BasePermission):
  19. """
  20. Allows access only with login token (.mfa is not None).
  21. DRF permission negation is flawed, so ~IsAPIToken does not give the correct behavior:
  22. https://github.com/encode/django-rest-framework/issues/6598#issuecomment-484824743
  23. """
  24. message = "Login token required."
  25. code = "login_token_required"
  26. def has_permission(self, request, view):
  27. return request.auth.mfa is not None
  28. class MFARequiredIfEnabled(permissions.BasePermission):
  29. """
  30. Allows access only to when
  31. - the token is a human token that has passed MFA, or
  32. - the token is a human token that has not passed MFA, but the user has not enabled MFA at all.
  33. """
  34. message = "Multi-factor authentication required."
  35. code = "mfa_required"
  36. def has_permission(self, request, view):
  37. return request.auth.mfa or (
  38. request.auth.mfa is False and not request.user.mfa_enabled
  39. )
  40. class IsOwner(permissions.BasePermission):
  41. """
  42. Custom permission to only allow owners of an object to view or edit it.
  43. """
  44. def has_object_permission(self, request, view, obj):
  45. return obj.owner == request.user
  46. class IsDomainOwner(permissions.BasePermission):
  47. """
  48. Custom permission to only allow owners of a domain to view or edit an object owned by that domain.
  49. """
  50. def has_object_permission(self, request, view, obj):
  51. return obj.domain.owner == request.user
  52. class TokenNoDomainPolicy(permissions.BasePermission):
  53. """
  54. Permission to check whether a token is unrestricted by any domain policy.
  55. """
  56. def has_permission(self, request, view):
  57. return request.auth.get_policy(domain=None) is None
  58. class TokenDomainPolicyBasePermission(permissions.BasePermission):
  59. """
  60. Base permission to check whether a token authorizes specific actions on a domain.
  61. """
  62. perm_field = None
  63. def _has_object_permission(self, request, view, obj):
  64. policy = request.auth.get_policy(domain=obj)
  65. # If the token has no domain policy, there are no restrictions
  66. if policy is None:
  67. return True
  68. # Otherwise, return the requested permission
  69. return getattr(policy, self.perm_field)
  70. class TokenHasDomainBasePermission(TokenDomainPolicyBasePermission):
  71. """
  72. Base permission for checking a token's domain policy, for the view domain.
  73. """
  74. def has_permission(self, request, view):
  75. return self._has_object_permission(request, view, view.domain)
  76. class TokenHasDomainDynDNSPermission(TokenHasDomainBasePermission):
  77. """
  78. Custom permission to check whether a token authorizes using the dynDNS interface for the view domain.
  79. """
  80. perm_field = "perm_dyndns"
  81. class TokenHasDomainRRsetsPermission(TokenHasDomainBasePermission):
  82. """
  83. Custom permission to check whether a token authorizes accessing RRsets for the view domain.
  84. """
  85. perm_field = "perm_rrsets"
  86. class AuthTokenCorrespondsToViewToken(permissions.BasePermission):
  87. """
  88. Permission to check whether the view kwargs's token_id corresponds to the current token.
  89. """
  90. def has_permission(self, request, view):
  91. return view.kwargs["token_id"] == request.auth.pk
  92. class IsVPNClient(permissions.BasePermission):
  93. """
  94. Permission that requires that the user is accessing using an IP from the VPN net.
  95. """
  96. message = "Inadmissible client IP."
  97. def has_permission(self, request, view):
  98. ip = IPv4Address(request.META.get("REMOTE_ADDR"))
  99. return ip in IPv4Network("10.8.0.0/24")
  100. class HasManageTokensPermission(permissions.BasePermission):
  101. """
  102. Permission to check whether a token has "manage tokens" permission.
  103. """
  104. def has_permission(self, request, view):
  105. return request.auth.perm_manage_tokens
  106. class WithinDomainLimit(permissions.BasePermission):
  107. """
  108. Permission that requires that the user still has domain limit quota available.
  109. """
  110. message = (
  111. "Domain limit exceeded. Please contact support to create additional domains."
  112. )
  113. def has_permission(self, request, view):
  114. return (
  115. request.user.limit_domains is None
  116. or request.user.domains.count() < request.user.limit_domains
  117. )