mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-06 19:23:23 +02:00
Merge pull request #1550 from cisagov/es/993-restrict-withdrawing-request
#993 Prevent restricted users from withdrawing domain application
This commit is contained in:
commit
c22aff5531
6 changed files with 88 additions and 8 deletions
|
@ -114,7 +114,7 @@ class UserGroup(Group):
|
||||||
)
|
)
|
||||||
|
|
||||||
cisa_analysts_group.save()
|
cisa_analysts_group.save()
|
||||||
logger.debug("CISA Analyt permissions added to group " + cisa_analysts_group.name)
|
logger.debug("CISA Analyst permissions added to group " + cisa_analysts_group.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error creating analyst permissions group: {e}")
|
logger.error(f"Error creating analyst permissions group: {e}")
|
||||||
|
|
||||||
|
|
|
@ -2225,6 +2225,33 @@ class TestApplicationStatus(TestWithUser, WebTest):
|
||||||
home_page = self.app.get("/")
|
home_page = self.app.get("/")
|
||||||
self.assertContains(home_page, "Withdrawn")
|
self.assertContains(home_page, "Withdrawn")
|
||||||
|
|
||||||
|
def test_application_withdraw_no_permissions(self):
|
||||||
|
"""Can't withdraw applications as a restricted user."""
|
||||||
|
self.user.status = User.RESTRICTED
|
||||||
|
self.user.save()
|
||||||
|
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
|
||||||
|
application.save()
|
||||||
|
|
||||||
|
home_page = self.app.get("/")
|
||||||
|
self.assertContains(home_page, "city.gov")
|
||||||
|
# click the "Manage" link
|
||||||
|
detail_page = home_page.click("Manage", index=0)
|
||||||
|
self.assertContains(detail_page, "city.gov")
|
||||||
|
self.assertContains(detail_page, "city1.gov")
|
||||||
|
self.assertContains(detail_page, "Chief Tester")
|
||||||
|
self.assertContains(detail_page, "testy@town.com")
|
||||||
|
self.assertContains(detail_page, "Admin Tester")
|
||||||
|
self.assertContains(detail_page, "Status:")
|
||||||
|
# Restricted user trying to withdraw results in 403 error
|
||||||
|
with less_console_noise():
|
||||||
|
for url_name in [
|
||||||
|
"application-withdraw-confirmation",
|
||||||
|
"application-withdrawn",
|
||||||
|
]:
|
||||||
|
with self.subTest(url_name=url_name):
|
||||||
|
page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
|
||||||
|
self.assertEqual(page.status_code, 403)
|
||||||
|
|
||||||
def test_application_status_no_permissions(self):
|
def test_application_status_no_permissions(self):
|
||||||
"""Can't access applications without being the creator."""
|
"""Can't access applications without being the creator."""
|
||||||
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
|
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
|
||||||
|
|
|
@ -13,7 +13,11 @@ from registrar.models import DomainApplication
|
||||||
from registrar.utility import StrEnum
|
from registrar.utility import StrEnum
|
||||||
from registrar.views.utility import StepsHelper
|
from registrar.views.utility import StepsHelper
|
||||||
|
|
||||||
from .utility import DomainApplicationPermissionView, ApplicationWizardPermissionView
|
from .utility import (
|
||||||
|
DomainApplicationPermissionView,
|
||||||
|
DomainApplicationPermissionWithdrawView,
|
||||||
|
ApplicationWizardPermissionView,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -544,7 +548,7 @@ class ApplicationStatus(DomainApplicationPermissionView):
|
||||||
template_name = "application_status.html"
|
template_name = "application_status.html"
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWithdrawConfirmation(DomainApplicationPermissionView):
|
class ApplicationWithdrawConfirmation(DomainApplicationPermissionWithdrawView):
|
||||||
"""This page will ask user to confirm if they want to withdraw
|
"""This page will ask user to confirm if they want to withdraw
|
||||||
|
|
||||||
The DomainApplicationPermissionView restricts access so that only the
|
The DomainApplicationPermissionView restricts access so that only the
|
||||||
|
@ -554,7 +558,7 @@ class ApplicationWithdrawConfirmation(DomainApplicationPermissionView):
|
||||||
template_name = "application_withdraw_confirmation.html"
|
template_name = "application_withdraw_confirmation.html"
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWithdrawn(DomainApplicationPermissionView):
|
class ApplicationWithdrawn(DomainApplicationPermissionWithdrawView):
|
||||||
# this view renders no template
|
# this view renders no template
|
||||||
template_name = ""
|
template_name = ""
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from .always_404 import always_404
|
||||||
from .permission_views import (
|
from .permission_views import (
|
||||||
DomainPermissionView,
|
DomainPermissionView,
|
||||||
DomainApplicationPermissionView,
|
DomainApplicationPermissionView,
|
||||||
|
DomainApplicationPermissionWithdrawView,
|
||||||
DomainInvitationPermissionDeleteView,
|
DomainInvitationPermissionDeleteView,
|
||||||
ApplicationWizardPermissionView,
|
ApplicationWizardPermissionView,
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,7 +26,8 @@ class PermissionsLoginMixin(PermissionRequiredMixin):
|
||||||
|
|
||||||
class DomainPermission(PermissionsLoginMixin):
|
class DomainPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Does the logged-in user have access to this domain?"""
|
"""Permission mixin that redirects to domain if user has access,
|
||||||
|
otherwise 403"""
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
"""Check if this user has access to this domain.
|
"""Check if this user has access to this domain.
|
||||||
|
@ -134,7 +135,8 @@ class DomainPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
class DomainApplicationPermission(PermissionsLoginMixin):
|
class DomainApplicationPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Does the logged-in user have access to this domain application?"""
|
"""Permission mixin that redirects to domain application if user
|
||||||
|
has access, otherwise 403"""
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
"""Check if this user has access to this domain application.
|
"""Check if this user has access to this domain application.
|
||||||
|
@ -154,9 +156,33 @@ class DomainApplicationPermission(PermissionsLoginMixin):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
"""Permission mixin that redirects to withdraw action on domain application
|
||||||
|
if user has access, otherwise 403"""
|
||||||
|
|
||||||
|
def has_permission(self):
|
||||||
|
"""Check if this user has access to withdraw this domain application."""
|
||||||
|
if not self.request.user.is_authenticated:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# user needs to be the creator of the application
|
||||||
|
# this query is empty if there isn't a domain application with this
|
||||||
|
# id and this user as creator
|
||||||
|
if not DomainApplication.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Restricted users should not be able to withdraw domain requests
|
||||||
|
if self.request.user.is_restricted():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWizardPermission(PermissionsLoginMixin):
|
class ApplicationWizardPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Does the logged-in user have permission to start or edit an application?"""
|
"""Permission mixin that redirects to start or edit domain application if
|
||||||
|
user has access, otherwise 403"""
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
"""Check if this user has permission to start or edit an application.
|
"""Check if this user has permission to start or edit an application.
|
||||||
|
@ -173,7 +199,8 @@ class ApplicationWizardPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
class DomainInvitationPermission(PermissionsLoginMixin):
|
class DomainInvitationPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Does the logged-in user have access to this domain invitation?
|
"""Permission mixin that redirects to domain invitation if user has
|
||||||
|
access, otherwise 403"
|
||||||
|
|
||||||
A user has access to a domain invitation if they have a role on the
|
A user has access to a domain invitation if they have a role on the
|
||||||
associated domain.
|
associated domain.
|
||||||
|
|
|
@ -8,6 +8,7 @@ from registrar.models import Domain, DomainApplication, DomainInvitation
|
||||||
from .mixins import (
|
from .mixins import (
|
||||||
DomainPermission,
|
DomainPermission,
|
||||||
DomainApplicationPermission,
|
DomainApplicationPermission,
|
||||||
|
DomainApplicationPermissionWithdraw,
|
||||||
DomainInvitationPermission,
|
DomainInvitationPermission,
|
||||||
ApplicationWizardPermission,
|
ApplicationWizardPermission,
|
||||||
)
|
)
|
||||||
|
@ -74,6 +75,26 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC):
|
||||||
|
|
||||||
|
"""Abstract base view for domain application withdraw function
|
||||||
|
|
||||||
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
`template_name`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# DetailView property for what model this is viewing
|
||||||
|
model = DomainApplication
|
||||||
|
# variable name in template context for the model object
|
||||||
|
context_object_name = "domainapplication"
|
||||||
|
|
||||||
|
# Abstract property enforces NotImplementedError on an attribute.
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def template_name(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC):
|
class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract base view for the application form that enforces permissions
|
"""Abstract base view for the application form that enforces permissions
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue