diff --git a/authentik/policies/apps.py b/authentik/policies/apps.py index 0f6d6efe0d..8821ecf358 100644 --- a/authentik/policies/apps.py +++ b/authentik/policies/apps.py @@ -7,7 +7,6 @@ For example: The 'dummy' policy is available at `authentik.policies.dummy`. from prometheus_client import Gauge, Histogram from authentik.blueprints.apps import ManagedAppConfig -from authentik.tenants.flags import Flag GAUGE_POLICIES_CACHED = Gauge( "authentik_policies_cached", @@ -32,12 +31,6 @@ HIST_POLICIES_EXECUTION_TIME = Histogram( ) -class BufferedPolicyAccessViewFlag(Flag[bool], key="policies_buffered_access_view"): - - default = False - visibility = "public" - - class AuthentikPoliciesConfig(ManagedAppConfig): """authentik policies app config""" diff --git a/authentik/policies/tests/test_views.py b/authentik/policies/tests/test_views.py index 91926fa476..2a61f270ad 100644 --- a/authentik/policies/tests/test_views.py +++ b/authentik/policies/tests/test_views.py @@ -1,29 +1,19 @@ from django.http import Http404, HttpResponse from django.test import TestCase -from django.urls import reverse from authentik.blueprints.tests import apply_blueprint from authentik.core.models import Application, Group, Provider from authentik.core.tests.utils import ( RequestFactory, create_test_brand, - create_test_flow, create_test_user, ) from authentik.flows.models import Flow, FlowDesignation -from authentik.flows.planner import FlowPlan -from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.lib.generators import generate_id -from authentik.policies.apps import BufferedPolicyAccessViewFlag from authentik.policies.models import PolicyBinding from authentik.policies.views import ( - QS_BUFFER_ID, - SESSION_KEY_BUFFER, - BufferedPolicyAccessView, - BufferView, PolicyAccessView, ) -from authentik.tenants.flags import patch_flag class TestPolicyViews(TestCase): @@ -124,71 +114,3 @@ class TestPolicyViews(TestCase): res = TestView.as_view()(req) self.assertEqual(res.status_code, 302) self.assertEqual(res.url, "/if/flow/default-authentication-flow/?next=%2F") - - @patch_flag(BufferedPolicyAccessViewFlag, True) - def test_pav_buffer(self): - """Test simple policy access view""" - provider = Provider.objects.create( - name=generate_id(), - ) - app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider) - flow = create_test_flow(FlowDesignation.AUTHENTICATION) - - class TestView(BufferedPolicyAccessView): - def resolve_provider_application(self): - self.provider = provider - self.application = app - - def get(self, *args, **kwargs): - return HttpResponse("foo") - - req = self.factory.get("/") - req.session[SESSION_KEY_PLAN] = FlowPlan(flow.pk) - req.session.save() - res = TestView.as_view()(req) - self.assertEqual(res.status_code, 302) - self.assertTrue(res.url.startswith(reverse("authentik_policies:buffer"))) - - @patch_flag(BufferedPolicyAccessViewFlag, True) - @apply_blueprint("default/flow-default-authentication-flow.yaml") - def test_pav_buffer_skip(self): - """Test simple policy access view (skip buffer)""" - provider = Provider.objects.create( - name=generate_id(), - ) - app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider) - flow = Flow.objects.get(slug="default-authentication-flow") - - class TestView(BufferedPolicyAccessView): - def resolve_provider_application(self): - self.provider = provider - self.application = app - - def get(self, *args, **kwargs): - return HttpResponse("foo") - - req = self.factory.get("/?skip_buffer=true") - req.brand = create_test_brand(flow_authentication=flow) - req.session[SESSION_KEY_PLAN] = FlowPlan(flow.pk) - req.session.save() - res = TestView.as_view()(req) - self.assertEqual(res.status_code, 302) - self.assertTrue( - res.url.startswith(reverse("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})) - ) - - def test_buffer(self): - """Test buffer view""" - uid = generate_id() - req = self.factory.get(f"/?{QS_BUFFER_ID}={uid}") - ts = generate_id() - req.session[SESSION_KEY_BUFFER % uid] = { - "method": "get", - "body": {}, - "url": f"/{ts}", - } - req.session.save() - - res = BufferView.as_view()(req) - self.assertEqual(res.status_code, 200) - self.assertIn(ts, res.render().content.decode()) diff --git a/authentik/policies/views.py b/authentik/policies/views.py index b871eb64dd..ff78e89706 100644 --- a/authentik/policies/views.py +++ b/authentik/policies/views.py @@ -1,12 +1,10 @@ """authentik access helper classes""" from typing import Any -from uuid import uuid4 from django.contrib import messages from django.contrib.auth.mixins import AccessMixin from django.http import Http404, HttpRequest, HttpResponse, QueryDict -from django.shortcuts import redirect from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext as _ @@ -19,16 +17,13 @@ from authentik.flows.models import Flow, FlowDesignation from authentik.flows.planner import ( PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_POST, - FlowPlan, FlowPlanner, ) from authentik.flows.views.executor import ( - SESSION_KEY_PLAN, SESSION_KEY_POST, ToDefaultFlow, ) from authentik.lib.sentry import SentryIgnoredException -from authentik.policies.apps import BufferedPolicyAccessViewFlag from authentik.policies.denied import AccessDeniedResponse from authentik.policies.engine import PolicyEngine from authentik.policies.models import PolicyBindingModel @@ -194,39 +189,3 @@ class BufferView(TemplateView): kwargs["check_auth_url"] = reverse("authentik_api:user-me") kwargs["continue_url"] = url_with_qs(buffer["url"], **{QS_BUFFER_ID: buf_id}) return super().get_context_data(**kwargs) - - -class BufferedPolicyAccessView(PolicyAccessView): - """PolicyAccessView which buffers access requests in case the user is not logged in""" - - def handle_no_permission(self): - plan: FlowPlan | None = self.request.session.get(SESSION_KEY_PLAN) - if plan: - flow = Flow.objects.filter(pk=plan.flow_pk).first() - if not flow or flow.designation != FlowDesignation.AUTHENTICATION: - LOGGER.debug("Not buffering request, no flow or flow not for authentication") - return super().handle_no_permission() - if not plan: - LOGGER.debug("Not buffering request, no flow plan active") - return super().handle_no_permission() - if not BufferedPolicyAccessViewFlag.get(): - return super().handle_no_permission() - if self.request.GET.get(QS_SKIP_BUFFER): - LOGGER.debug("Not buffering request, explicit skip") - return super().handle_no_permission() - buffer_id = str(uuid4()) - LOGGER.debug("Buffering access request", bf_id=buffer_id) - self.request.session[SESSION_KEY_BUFFER % buffer_id] = { - "body": self.request.POST, - "url": self.request.build_absolute_uri(self.request.get_full_path()), - "method": self.request.method.lower(), - } - return redirect( - url_with_qs(reverse("authentik_policies:buffer"), **{QS_BUFFER_ID: buffer_id}) - ) - - def dispatch(self, request, *args, **kwargs): - response = super().dispatch(request, *args, **kwargs) - if QS_BUFFER_ID in self.request.GET: - self.request.session.pop(SESSION_KEY_BUFFER % self.request.GET[QS_BUFFER_ID], None) - return response diff --git a/authentik/providers/oauth2/views/authorize.py b/authentik/providers/oauth2/views/authorize.py index e263515ea8..3a8aee4820 100644 --- a/authentik/providers/oauth2/views/authorize.py +++ b/authentik/providers/oauth2/views/authorize.py @@ -45,7 +45,7 @@ from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, StageVie from authentik.lib.utils.time import timedelta_from_string from authentik.lib.views import bad_request_message from authentik.policies.types import PolicyRequest -from authentik.policies.views import BufferedPolicyAccessView, RequestValidationError +from authentik.policies.views import PolicyAccessView, RequestValidationError from authentik.providers.oauth2.errors import ( AuthorizeError, ClientIdError, @@ -338,7 +338,7 @@ class OAuthAuthorizationParams: return code -class AuthorizationFlowInitView(BufferedPolicyAccessView): +class AuthorizationFlowInitView(PolicyAccessView): """OAuth2 Flow initializer, checks access to application and starts flow""" params: OAuthAuthorizationParams diff --git a/authentik/providers/rac/views.py b/authentik/providers/rac/views.py index a2e51387e3..334edba760 100644 --- a/authentik/providers/rac/views.py +++ b/authentik/providers/rac/views.py @@ -18,14 +18,14 @@ from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner from authentik.flows.stage import RedirectStage from authentik.lib.utils.time import timedelta_from_string from authentik.policies.engine import PolicyEngine -from authentik.policies.views import BufferedPolicyAccessView +from authentik.policies.views import PolicyAccessView from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT PLAN_CONNECTION_SETTINGS = "connection_settings" -class RACStartView(BufferedPolicyAccessView): +class RACStartView(PolicyAccessView): """Start a RAC connection by checking access and creating a connection token""" endpoint: Endpoint diff --git a/authentik/providers/saml/views/sso.py b/authentik/providers/saml/views/sso.py index 076fb68706..cdffa9afb6 100644 --- a/authentik/providers/saml/views/sso.py +++ b/authentik/providers/saml/views/sso.py @@ -15,7 +15,7 @@ from authentik.flows.models import in_memory_stage from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner from authentik.flows.views.executor import SESSION_KEY_POST from authentik.lib.views import bad_request_message -from authentik.policies.views import BufferedPolicyAccessView +from authentik.policies.views import PolicyAccessView from authentik.providers.saml.exceptions import CannotHandleAssertion from authentik.providers.saml.models import SAMLBindings, SAMLProvider from authentik.providers.saml.processors.authn_request_parser import AuthNRequestParser @@ -35,7 +35,7 @@ from authentik.stages.consent.stage import ( LOGGER = get_logger() -class SAMLSSOView(BufferedPolicyAccessView): +class SAMLSSOView(PolicyAccessView): """SAML SSO Base View, which plans a flow and injects our final stage. Calls get/post handler.""" @@ -88,7 +88,7 @@ class SAMLSSOView(BufferedPolicyAccessView): def post(self, request: HttpRequest, application_slug: str) -> HttpResponse: """GET and POST use the same handler, but we can't - override .dispatch easily because BufferedPolicyAccessView's dispatch""" + override .dispatch easily because PolicyAccessView's dispatch""" return self.get(request, application_slug) diff --git a/schema.yml b/schema.yml index 9cf5f5898a..6043c5aa5f 100644 --- a/schema.yml +++ b/schema.yml @@ -37002,8 +37002,6 @@ components: properties: enterprise_audit_include_expanded_diff: type: boolean - policies_buffered_access_view: - type: boolean flows_continuous_login: type: boolean flows_refresh_others: @@ -37012,7 +37010,6 @@ components: - enterprise_audit_include_expanded_diff - flows_continuous_login - flows_refresh_others - - policies_buffered_access_view readOnly: true required: - branding_custom_css @@ -50779,8 +50776,6 @@ components: properties: enterprise_audit_include_expanded_diff: type: boolean - policies_buffered_access_view: - type: boolean flows_continuous_login: type: boolean flows_refresh_others: @@ -50789,7 +50784,6 @@ components: - enterprise_audit_include_expanded_diff - flows_continuous_login - flows_refresh_others - - policies_buffered_access_view PatchedSourceStageRequest: type: object description: SourceStage Serializer @@ -55481,8 +55475,6 @@ components: properties: enterprise_audit_include_expanded_diff: type: boolean - policies_buffered_access_view: - type: boolean flows_continuous_login: type: boolean flows_refresh_others: @@ -55491,7 +55483,6 @@ components: - enterprise_audit_include_expanded_diff - flows_continuous_login - flows_refresh_others - - policies_buffered_access_view required: - flags SettingsRequest: @@ -55562,8 +55553,6 @@ components: properties: enterprise_audit_include_expanded_diff: type: boolean - policies_buffered_access_view: - type: boolean flows_continuous_login: type: boolean flows_refresh_others: @@ -55572,7 +55561,6 @@ components: - enterprise_audit_include_expanded_diff - flows_continuous_login - flows_refresh_others - - policies_buffered_access_view required: - flags SeverityEnum: diff --git a/tests/e2e/test_provider_oauth2_grafana.py b/tests/e2e/test_provider_oauth2_grafana.py index b8a4b07d23..63665a6734 100644 --- a/tests/e2e/test_provider_oauth2_grafana.py +++ b/tests/e2e/test_provider_oauth2_grafana.py @@ -1,7 +1,6 @@ """test OAuth2 OpenID Provider flow""" from time import sleep -from unittest import skip from docker.types import Healthcheck from selenium.webdriver.common.by import By @@ -18,7 +17,6 @@ from authentik.core.models import Application from authentik.core.tests.utils import create_test_cert from authentik.flows.models import Flow from authentik.lib.generators import generate_id, generate_key -from authentik.policies.apps import BufferedPolicyAccessViewFlag from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.models import PolicyBinding from authentik.providers.oauth2.models import ( @@ -28,7 +26,6 @@ from authentik.providers.oauth2.models import ( RedirectURIMatchingMode, ScopeMapping, ) -from authentik.tenants.flags import patch_flag from tests.e2e.utils import SeleniumTestCase, retry @@ -415,79 +412,3 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): self.driver.find_element(By.CSS_SELECTOR, "[data-test-id='card-title']").text, "Permission denied", ) - - @skip("Flaky test") - @retry() - @apply_blueprint( - "default/flow-default-authentication-flow.yaml", - "default/flow-default-invalidation-flow.yaml", - ) - @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml") - @apply_blueprint("system/providers-oauth2.yaml") - @reconcile_app("authentik_crypto") - @patch_flag(BufferedPolicyAccessViewFlag, True) - def test_authorization_consent_implied_parallel(self): - """test OpenID Provider flow (default authorization flow with implied consent)""" - # Bootstrap all needed objects - authorization_flow = Flow.objects.get( - slug="default-provider-authorization-implicit-consent" - ) - provider = OAuth2Provider.objects.create( - name=generate_id(), - client_type=ClientTypes.CONFIDENTIAL, - client_id=self.client_id, - client_secret=self.client_secret, - signing_key=create_test_cert(), - redirect_uris=[ - RedirectURI( - RedirectURIMatchingMode.STRICT, "http://localhost:3000/login/generic_oauth" - ) - ], - authorization_flow=authorization_flow, - ) - provider.property_mappings.set( - ScopeMapping.objects.filter( - scope_name__in=[ - SCOPE_OPENID, - SCOPE_OPENID_EMAIL, - SCOPE_OPENID_PROFILE, - SCOPE_OFFLINE_ACCESS, - ] - ) - ) - Application.objects.create( - name=generate_id(), - slug=self.app_slug, - provider=provider, - ) - - self.driver.get(self.live_server_url) - login_window = self.driver.current_window_handle - - self.driver.switch_to.new_window("tab") - grafana_window = self.driver.current_window_handle - self.driver.get("http://localhost:3000") - self.driver.find_element(By.CLASS_NAME, "btn-service--oauth").click() - - self.driver.switch_to.window(login_window) - self.login() - - self.driver.switch_to.window(grafana_window) - self.wait_for_url("http://localhost:3000/?orgId=1") - self.driver.get("http://localhost:3000/profile") - self.assertEqual( - self.driver.find_element(By.CLASS_NAME, "page-header__title").text, - self.user.name, - ) - self.assertEqual( - self.driver.find_element(By.CSS_SELECTOR, "input[name=name]").get_attribute("value"), - self.user.name, - ) - self.assertEqual( - self.driver.find_element(By.CSS_SELECTOR, "input[name=email]").get_attribute("value"), - self.user.email, - ) - self.assertEqual( - self.driver.find_element(By.CSS_SELECTOR, "input[name=login]").get_attribute("value"), - self.user.email, - ) diff --git a/tests/e2e/test_provider_saml.py b/tests/e2e/test_provider_saml.py index 60c3472086..8cb2273570 100644 --- a/tests/e2e/test_provider_saml.py +++ b/tests/e2e/test_provider_saml.py @@ -2,7 +2,6 @@ from json import dumps from time import sleep -from unittest import skip from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec @@ -13,11 +12,9 @@ from authentik.core.models import Application from authentik.core.tests.utils import create_test_cert from authentik.flows.models import Flow from authentik.lib.generators import generate_id -from authentik.policies.apps import BufferedPolicyAccessViewFlag from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.models import PolicyBinding from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider -from authentik.tenants.flags import patch_flag from tests.e2e.utils import SeleniumTestCase, retry @@ -582,111 +579,3 @@ class TestProviderSAML(SeleniumTestCase): lambda driver: driver.current_url.startswith(should_url), f"URL {self.driver.current_url} doesn't match expected URL {should_url}", ) - - @skip("Flaky test") - @retry() - @apply_blueprint( - "default/flow-default-authentication-flow.yaml", - "default/flow-default-invalidation-flow.yaml", - ) - @apply_blueprint( - "default/flow-default-provider-authorization-implicit-consent.yaml", - ) - @apply_blueprint( - "system/providers-saml.yaml", - ) - @reconcile_app("authentik_crypto") - @patch_flag(BufferedPolicyAccessViewFlag, True) - def test_sp_initiated_implicit_post_buffer(self): - """test SAML Provider flow SP-initiated flow (implicit consent)""" - # Bootstrap all needed objects - authorization_flow = Flow.objects.get( - slug="default-provider-authorization-implicit-consent" - ) - provider: SAMLProvider = SAMLProvider.objects.create( - name=generate_id(), - acs_url=f"http://{self.host}:9009/saml/acs", - audience="authentik-e2e", - issuer="authentik-e2e", - sp_binding=SAMLBindings.POST, - authorization_flow=authorization_flow, - signing_kp=create_test_cert(), - ) - provider.property_mappings.set(SAMLPropertyMapping.objects.all()) - provider.save() - Application.objects.create( - name="SAML", - slug=generate_id(), - provider=provider, - ) - self.setup_client(provider, True, SP_ROOT_URL=f"http://{self.host}:9009") - - self.driver.get(self.live_server_url) - login_window = self.driver.current_window_handle - self.driver.switch_to.new_window("tab") - client_window = self.driver.current_window_handle - # We need to access the SP on the same host as the IdP for SameSite cookies - self.driver.get(f"http://{self.host}:9009") - self.driver.switch_to.new_window("tab") - client_window = self.driver.current_window_handle - # We need to access the SP on the same host as the IdP for SameSite cookies - self.driver.get(f"http://{self.host}:9009") - self.driver.switch_to.new_window("tab") - client_window = self.driver.current_window_handle - # We need to access the SP on the same host as the IdP for SameSite cookies - self.driver.get(f"http://{self.host}:9009") - self.driver.switch_to.new_window("tab") - client_window = self.driver.current_window_handle - # We need to access the SP on the same host as the IdP for SameSite cookies - self.driver.get(f"http://{self.host}:9009") - self.driver.switch_to.new_window("tab") - client_window = self.driver.current_window_handle - # We need to access the SP on the same host as the IdP for SameSite cookies - self.driver.get(f"http://{self.host}:9009") - - self.driver.switch_to.window(login_window) - self.login() - self.driver.switch_to.window(client_window) - - self.wait_for_url(f"http://{self.host}:9009/") - - body = self.parse_json_content() - snippet = dumps(body, indent=2)[:500].replace("\n", " ") - attrs = body.get("attr", {}) - - self.assertEqual( - attrs.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"), - [self.user.name], - f"Claim 'name' mismatch at {self.driver.current_url}: {snippet}", - ) - - self.assertEqual( - attrs.get("http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"), - [self.user.username], - f"Claim 'windowsaccountname' mismatch at {self.driver.current_url}: {snippet}", - ) - - self.assertEqual( - attrs.get("http://schemas.goauthentik.io/2021/02/saml/username"), - [self.user.username], - f"Claim 'username' mismatch at {self.driver.current_url}: {snippet}", - ) - - self.assertEqual( - attrs.get("http://schemas.goauthentik.io/2021/02/saml/uid"), - [str(self.user.pk)], - f"Claim 'uid' mismatch at {self.driver.current_url}: {snippet}", - ) - - self.assertEqual( - attrs.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), - [self.user.email], - f"Claim 'emailaddress' mismatch at {self.driver.current_url}: {snippet}", - ) - - self.assertEqual( - attrs.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"), - [self.user.email], - f"Claim 'upn' mismatch at {self.driver.current_url}: {snippet}", - ) - sleep(3) diff --git a/web/src/admin/admin-settings/AdminSettingsForm.ts b/web/src/admin/admin-settings/AdminSettingsForm.ts index 0de6267c88..84440fa5b6 100644 --- a/web/src/admin/admin-settings/AdminSettingsForm.ts +++ b/web/src/admin/admin-settings/AdminSettingsForm.ts @@ -266,15 +266,6 @@ export class AdminSettingsForm extends Form { )} >
- -