permissions.py 4.1 KB

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