diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 481221f50..e0e56c683 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,7 +152,7 @@ jobs: - uses: actions/upload-artifact@v2 if: failure() with: - path: out/ + path: selenium_screenshots/ - name: Create XML Report run: pipenv run coverage xml - uses: codecov/codecov-action@v1 diff --git a/.gitignore b/.gitignore index d6e348963..606885d70 100644 --- a/.gitignore +++ b/.gitignore @@ -196,3 +196,6 @@ local.env.yml ### Helm ### # Chart dependencies **/charts/*.tgz + +# Selenium Screenshots +selenium_screenshots/** diff --git a/e2e/test_provider_oauth.py b/e2e/test_provider_oauth.py index 49152c263..8960ac65d 100644 --- a/e2e/test_provider_oauth.py +++ b/e2e/test_provider_oauth.py @@ -11,6 +11,8 @@ from docker.types import Healthcheck from e2e.utils import USER, SeleniumTestCase from passbook.core.models import Application from passbook.flows.models import Flow +from passbook.policies.expression.models import ExpressionPolicy +from passbook.policies.models import PolicyBinding from passbook.providers.oauth.models import OAuth2Provider @@ -192,3 +194,42 @@ class TestProviderOAuth(SeleniumTestCase): ).get_attribute("value"), USER().username, ) + + def test_denied(self): + """test OAuth Provider flow (default authorization flow, denied)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-explicit-consent" + ) + provider = OAuth2Provider.objects.create( + name="grafana", + client_type=OAuth2Provider.CLIENT_CONFIDENTIAL, + authorization_grant_type=OAuth2Provider.GRANT_AUTHORIZATION_CODE, + client_id=self.client_id, + client_secret=self.client_secret, + redirect_uris="http://localhost:3000/login/github", + skip_authorization=True, + authorization_flow=authorization_flow, + ) + app = Application.objects.create( + name="Grafana", slug="grafana", provider=provider, + ) + + negative_policy = ExpressionPolicy.objects.create( + name="negative-static", expression="return False" + ) + PolicyBinding.objects.create(target=app, policy=negative_policy, order=0) + + self.driver.get("http://localhost:3000") + self.driver.find_element(By.CLASS_NAME, "btn-service--github").click() + self.driver.find_element(By.ID, "id_uid_field").click() + self.driver.find_element(By.ID, "id_uid_field").send_keys(USER().username) + self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) + self.driver.find_element(By.ID, "id_password").send_keys(USER().username) + self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) + self.wait_for_url(self.url("passbook_flows:denied")) + self.assertEqual( + self.driver.find_element(By.CSS_SELECTOR, "#flow-body > header > h1").text, + "Permission denied", + ) diff --git a/e2e/test_provider_oidc.py b/e2e/test_provider_oidc.py index 3c44b9544..1ccdffdbb 100644 --- a/e2e/test_provider_oidc.py +++ b/e2e/test_provider_oidc.py @@ -14,6 +14,8 @@ from docker.types import Healthcheck from e2e.utils import USER, SeleniumTestCase, ensure_rsa_key from passbook.core.models import Application from passbook.flows.models import Flow +from passbook.policies.expression.models import ExpressionPolicy +from passbook.policies.models import PolicyBinding from passbook.providers.oidc.models import OpenIDProvider @@ -252,3 +254,50 @@ class TestProviderOIDC(SeleniumTestCase): ).get_attribute("value"), USER().email, ) + + def test_authorization_denied(self): + """test OpenID Provider flow (default authorization with access deny)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-explicit-consent" + ) + client = Client.objects.create( + name="grafana", + client_type="confidential", + client_id=self.client_id, + client_secret=self.client_secret, + _redirect_uris="http://localhost:3000/login/generic_oauth", + _scope="openid profile email", + reuse_consent=False, + require_consent=False, + ) + # At least one of these objects must exist + ensure_rsa_key() + # This response_code object might exist or not, depending on the order the tests are run + rp_type, _ = ResponseType.objects.get_or_create(value="code") + client.response_types.set([rp_type]) + client.save() + provider = OpenIDProvider.objects.create( + oidc_client=client, authorization_flow=authorization_flow, + ) + app = Application.objects.create( + name="Grafana", slug="grafana", provider=provider, + ) + + negative_policy = ExpressionPolicy.objects.create( + name="negative-static", expression="return False" + ) + PolicyBinding.objects.create(target=app, policy=negative_policy, order=0) + self.driver.get("http://localhost:3000") + self.driver.find_element(By.CLASS_NAME, "btn-service--oauth").click() + self.driver.find_element(By.ID, "id_uid_field").click() + self.driver.find_element(By.ID, "id_uid_field").send_keys(USER().username) + self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) + self.driver.find_element(By.ID, "id_password").send_keys(USER().username) + self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) + self.wait_for_url(self.url("passbook_flows:denied")) + self.assertEqual( + self.driver.find_element(By.CSS_SELECTOR, "#flow-body > header > h1").text, + "Permission denied", + ) diff --git a/e2e/utils.py b/e2e/utils.py index 7c10ad47e..76ae1aec0 100644 --- a/e2e/utils.py +++ b/e2e/utils.py @@ -43,7 +43,7 @@ class SeleniumTestCase(StaticLiveServerTestCase): def setUp(self): super().setUp() - makedirs("out", exist_ok=True) + makedirs("selenium_screenshots/", exist_ok=True) self.driver = self._get_driver() self.driver.maximize_window() self.driver.implicitly_wait(300) @@ -58,7 +58,7 @@ class SeleniumTestCase(StaticLiveServerTestCase): ) def tearDown(self): - self.driver.save_screenshot(f"out/{self.__class__.__name__}_{time()}.png") + self.driver.save_screenshot(f"selenium_screenshots/{self.__class__.__name__}_{time()}.png") for line in self.driver.get_log("browser"): self.logger.warning( line["message"], source=line["source"], level=line["level"]