diff --git a/e2e/test_provider_proxy.py b/e2e/test_provider_proxy.py index bc90d3c8a..617b65178 100644 --- a/e2e/test_provider_proxy.py +++ b/e2e/test_provider_proxy.py @@ -1,6 +1,8 @@ """Proxy and Outpost e2e tests""" +from sys import platform from time import sleep from typing import Any, Dict, Optional +from unittest.case import skipUnless from docker.client import DockerClient, from_env from docker.models.containers import Container @@ -14,6 +16,7 @@ from passbook.outposts.models import Outpost, OutpostDeploymentType, OutpostType from passbook.providers.proxy.models import ProxyProvider +@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderProxy(SeleniumTestCase): """Proxy and Outpost e2e tests""" diff --git a/e2e/utils.py b/e2e/utils.py index 5592c6a68..f48d3aaa1 100644 --- a/e2e/utils.py +++ b/e2e/utils.py @@ -17,7 +17,6 @@ from docker.models.containers import Container from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.ui import WebDriverWait from structlog import get_logger @@ -91,7 +90,7 @@ class SeleniumTestCase(StaticLiveServerTestCase): def wait_for_url(self, desired_url): """Wait until URL is `desired_url`.""" self.wait.until( - ec.url_to_be(desired_url), + lambda driver: driver.current_url == desired_url, f"URL {self.driver.current_url} doesn't match expected URL {desired_url}", ) diff --git a/passbook/core/migrations/0009_group_is_superuser.py b/passbook/core/migrations/0009_group_is_superuser.py index a69a3ebbb..cc7fcc497 100644 --- a/passbook/core/migrations/0009_group_is_superuser.py +++ b/passbook/core/migrations/0009_group_is_superuser.py @@ -3,6 +3,8 @@ from django.apps.registry import Apps from django.db import migrations, models from django.db.backends.base.schema import BaseDatabaseSchemaEditor +import passbook.core.models + def create_default_admin_group(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): db_alias = schema_editor.connection.alias @@ -42,9 +44,6 @@ class Migration(migrations.Migration): ), migrations.RunPython(create_default_admin_group), migrations.AlterModelManagers( - name='user', - managers=[ - ('objects', passbook.core.models.UserManager()), - ], + name="user", managers=[("objects", passbook.core.models.UserManager()),], ), ] diff --git a/passbook/providers/oauth2/migrations/0003_auto_20200916_2129.py b/passbook/providers/oauth2/migrations/0003_auto_20200916_2129.py index b1d37983c..1f2f806ff 100644 --- a/passbook/providers/oauth2/migrations/0003_auto_20200916_2129.py +++ b/passbook/providers/oauth2/migrations/0003_auto_20200916_2129.py @@ -6,18 +6,39 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('passbook_providers_oauth2', '0002_oauth2provider_sub_mode'), + ("passbook_providers_oauth2", "0002_oauth2provider_sub_mode"), ] operations = [ migrations.AlterField( - model_name='oauth2provider', - name='client_type', - field=models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], default='confidential', help_text='Confidential clients are capable of maintaining the confidentiality\n of their credentials. Public clients are incapable.', max_length=30, verbose_name='Client Type'), + model_name="oauth2provider", + name="client_type", + field=models.CharField( + choices=[("confidential", "Confidential"), ("public", "Public")], + default="confidential", + help_text="Confidential clients are capable of maintaining the confidentiality\n of their credentials. Public clients are incapable.", + max_length=30, + verbose_name="Client Type", + ), ), migrations.AlterField( - model_name='oauth2provider', - name='response_type', - field=models.TextField(choices=[('code', 'code (Authorization Code Flow)'), ('code_adfs', 'code (ADFS Compatibility Mode, sends id_token as access_token)'), ('id_token', 'id_token (Implicit Flow)'), ('id_token token', 'id_token token (Implicit Flow)'), ('code token', 'code token (Hybrid Flow)'), ('code id_token', 'code id_token (Hybrid Flow)'), ('code id_token token', 'code id_token token (Hybrid Flow)')], default='code', help_text='Response Type required by the client.'), + model_name="oauth2provider", + name="response_type", + field=models.TextField( + choices=[ + ("code", "code (Authorization Code Flow)"), + ( + "code_adfs", + "code (ADFS Compatibility Mode, sends id_token as access_token)", + ), + ("id_token", "id_token (Implicit Flow)"), + ("id_token token", "id_token token (Implicit Flow)"), + ("code token", "code token (Hybrid Flow)"), + ("code id_token", "code id_token (Hybrid Flow)"), + ("code id_token token", "code id_token token (Hybrid Flow)"), + ], + default="code", + help_text="Response Type required by the client.", + ), ), ] diff --git a/passbook/providers/oauth2/models.py b/passbook/providers/oauth2/models.py index 6f15f4282..8d904c83b 100644 --- a/passbook/providers/oauth2/models.py +++ b/passbook/providers/oauth2/models.py @@ -70,7 +70,10 @@ class ResponseTypes(models.TextChoices): """Response Type required by the client.""" CODE = "code", _("code (Authorization Code Flow)") - CODE_ADFS = "code_adfs", _("code (ADFS Compatibility Mode, sends id_token as access_token)") + CODE_ADFS = ( + "code_adfs", + _("code (ADFS Compatibility Mode, sends id_token as access_token)"), + ) ID_TOKEN = "id_token", _("id_token (Implicit Flow)") ID_TOKEN_TOKEN = "id_token token", _("id_token token (Implicit Flow)") CODE_TOKEN = "code token", _("code token (Hybrid Flow)") diff --git a/passbook/providers/oauth2/utils.py b/passbook/providers/oauth2/utils.py index 6d5a18e30..909725a27 100644 --- a/passbook/providers/oauth2/utils.py +++ b/passbook/providers/oauth2/utils.py @@ -61,11 +61,12 @@ def extract_access_token(request: HttpRequest) -> str: auth_header = request.META.get("HTTP_AUTHORIZATION", "") if re.compile(r"^[Bb]earer\s{1}.+$").match(auth_header): - access_token = auth_header.split()[1] - else: - access_token = request.GET.get("access_token", "") - - return access_token + return auth_header.split()[1] + if "access_token" in request.POST: + return request.POST.get("access_token") + if "access_token" in request.GET: + return request.GET.get("access_token") + return "" def extract_client_auth(request: HttpRequest) -> Tuple[str, str]: diff --git a/passbook/providers/oauth2/views/token.py b/passbook/providers/oauth2/views/token.py index 84eb4262d..2ff9e4683 100644 --- a/passbook/providers/oauth2/views/token.py +++ b/passbook/providers/oauth2/views/token.py @@ -17,7 +17,8 @@ from passbook.providers.oauth2.errors import TokenError, UserAuthError from passbook.providers.oauth2.models import ( AuthorizationCode, OAuth2Provider, - RefreshToken, ResponseTypes, + RefreshToken, + ResponseTypes, ) from passbook.providers.oauth2.utils import TokenResponse, extract_client_auth diff --git a/swagger.yaml b/swagger.yaml index ac57ced14..523dd7575 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -6605,8 +6605,8 @@ definitions: client_type: title: Client Type description: |- - Confidential clients are capable of maintaining the confidentiality - of their credentials. Public clients are incapable. + Confidential clients are capable of maintaining the confidentiality + of their credentials. Public clients are incapable. type: string enum: - confidential @@ -6626,6 +6626,7 @@ definitions: type: string enum: - code + - code_adfs - id_token - id_token token - code token