*: apply new black styling

This commit is contained in:
Jens Langhammer 2020-09-30 19:34:22 +02:00
parent 9ef39f1e04
commit 525d271535
80 changed files with 485 additions and 163 deletions

View file

@ -104,7 +104,8 @@ class TestFlowsEnroll(SeleniumTestCase):
self.wait_for_url(self.url("passbook_core:user-settings")) self.wait_for_url(self.url("passbook_core:user-settings"))
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, "foo", self.driver.find_element(By.ID, "user-settings").text,
"foo",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
@ -208,7 +209,8 @@ class TestFlowsEnroll(SeleniumTestCase):
self.driver.find_element(By.ID, "user-settings").click() self.driver.find_element(By.ID, "user-settings").click()
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, "foo", self.driver.find_element(By.ID, "user-settings").text,
"foo",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"

View file

@ -21,5 +21,6 @@ class TestFlowsLogin(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) 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.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, USER().username, self.driver.find_element(By.ID, "user-settings").text,
USER().username,
) )

View file

@ -48,7 +48,8 @@ class TestFlowsOTP(SeleniumTestCase):
self.driver.find_element(By.ID, "id_code").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_code").send_keys(Keys.ENTER)
self.wait_for_url(self.url("passbook_core:overview")) self.wait_for_url(self.url("passbook_core:overview"))
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, USER().username, self.driver.find_element(By.ID, "user-settings").text,
USER().username,
) )
def test_otp_totp_setup(self): def test_otp_totp_setup(self):
@ -62,7 +63,8 @@ class TestFlowsOTP(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) 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.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, USER().username, self.driver.find_element(By.ID, "user-settings").text,
USER().username,
) )
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click() self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()
@ -107,7 +109,8 @@ class TestFlowsOTP(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) 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.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, USER().username, self.driver.find_element(By.ID, "user-settings").text,
USER().username,
) )
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click() self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()

View file

@ -77,7 +77,9 @@ class TestProviderOAuth2Github(SeleniumTestCase):
authorization_flow=authorization_flow, authorization_flow=authorization_flow,
) )
Application.objects.create( Application.objects.create(
name="Grafana", slug="grafana", provider=provider, name="Grafana",
slug="grafana",
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -129,7 +131,9 @@ class TestProviderOAuth2Github(SeleniumTestCase):
authorization_flow=authorization_flow, authorization_flow=authorization_flow,
) )
app = Application.objects.create( app = Application.objects.create(
name="Grafana", slug="grafana", provider=provider, name="Grafana",
slug="grafana",
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -143,13 +147,17 @@ class TestProviderOAuth2Github(SeleniumTestCase):
sleep(1) sleep(1)
self.assertEqual( self.assertEqual(
app.name, self.driver.find_element(By.ID, "application-name").text, app.name,
self.driver.find_element(By.ID, "application-name").text,
) )
self.assertEqual( self.assertEqual(
"GitHub Compatibility: Access you Email addresses", "GitHub Compatibility: Access you Email addresses",
self.driver.find_element(By.ID, "scope-user:email").text, self.driver.find_element(By.ID, "scope-user:email").text,
) )
self.driver.find_element(By.CSS_SELECTOR, ("[type=submit]"),).click() self.driver.find_element(
By.CSS_SELECTOR,
("[type=submit]"),
).click()
self.wait_for_url("http://localhost:3000/?orgId=1") self.wait_for_url("http://localhost:3000/?orgId=1")
self.driver.get("http://localhost:3000/profile") self.driver.get("http://localhost:3000/profile")
@ -192,7 +200,9 @@ class TestProviderOAuth2Github(SeleniumTestCase):
authorization_flow=authorization_flow, authorization_flow=authorization_flow,
) )
app = Application.objects.create( app = Application.objects.create(
name="Grafana", slug="grafana", provider=provider, name="Grafana",
slug="grafana",
provider=provider,
) )
negative_policy = ExpressionPolicy.objects.create( negative_policy = ExpressionPolicy.objects.create(

View file

@ -104,7 +104,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
) )
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name="Grafana", slug=APPLICATION_SLUG, provider=provider, name="Grafana",
slug=APPLICATION_SLUG,
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -144,7 +146,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
) )
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name="Grafana", slug=APPLICATION_SLUG, provider=provider, name="Grafana",
slug=APPLICATION_SLUG,
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -203,7 +207,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
) )
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name="Grafana", slug=APPLICATION_SLUG, provider=provider, name="Grafana",
slug=APPLICATION_SLUG,
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -270,7 +276,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
) )
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name="Grafana", slug=APPLICATION_SLUG, provider=provider, name="Grafana",
slug=APPLICATION_SLUG,
provider=provider,
) )
self.driver.get("http://localhost:3000") self.driver.get("http://localhost:3000")
@ -282,7 +290,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
app.name, self.driver.find_element(By.ID, "application-name").text, app.name,
self.driver.find_element(By.ID, "application-name").text,
) )
self.wait.until( self.wait.until(
ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]")) ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]"))
@ -340,7 +349,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
) )
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name="Grafana", slug=APPLICATION_SLUG, provider=provider, name="Grafana",
slug=APPLICATION_SLUG,
provider=provider,
) )
negative_policy = ExpressionPolicy.objects.create( negative_policy = ExpressionPolicy.objects.create(

View file

@ -100,7 +100,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
) )
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name=self.application_slug, slug=self.application_slug, provider=provider, name=self.application_slug,
slug=self.application_slug,
provider=provider,
) )
self.container = self.setup_client() self.container = self.setup_client()
@ -141,7 +143,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
) )
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name=self.application_slug, slug=self.application_slug, provider=provider, name=self.application_slug,
slug=self.application_slug,
provider=provider,
) )
self.container = self.setup_client() self.container = self.setup_client()
@ -189,7 +193,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
) )
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name=self.application_slug, slug=self.application_slug, provider=provider, name=self.application_slug,
slug=self.application_slug,
provider=provider,
) )
self.container = self.setup_client() self.container = self.setup_client()
@ -202,7 +208,8 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
app.name, self.driver.find_element(By.ID, "application-name").text, app.name,
self.driver.find_element(By.ID, "application-name").text,
) )
self.wait.until( self.wait.until(
ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]")) ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]"))
@ -246,7 +253,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
) )
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name=self.application_slug, slug=self.application_slug, provider=provider, name=self.application_slug,
slug=self.application_slug,
provider=provider,
) )
negative_policy = ExpressionPolicy.objects.create( negative_policy = ExpressionPolicy.objects.create(

View file

@ -84,7 +84,9 @@ class TestProviderSAML(SeleniumTestCase):
provider.property_mappings.set(SAMLPropertyMapping.objects.all()) provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name="SAML", slug="passbook-saml", provider=provider, name="SAML",
slug="passbook-saml",
provider=provider,
) )
self.container = self.setup_client(provider) self.container = self.setup_client(provider)
self.driver.get("http://localhost:9009") self.driver.get("http://localhost:9009")
@ -121,7 +123,9 @@ class TestProviderSAML(SeleniumTestCase):
provider.property_mappings.set(SAMLPropertyMapping.objects.all()) provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name="SAML", slug="passbook-saml", provider=provider, name="SAML",
slug="passbook-saml",
provider=provider,
) )
self.container = self.setup_client(provider) self.container = self.setup_client(provider)
self.driver.get("http://localhost:9009") self.driver.get("http://localhost:9009")
@ -131,7 +135,8 @@ class TestProviderSAML(SeleniumTestCase):
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) 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.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.assertEqual(
app.name, self.driver.find_element(By.ID, "application-name").text, app.name,
self.driver.find_element(By.ID, "application-name").text,
) )
sleep(1) sleep(1)
self.driver.find_element(By.CSS_SELECTOR, "[type=submit]").click() self.driver.find_element(By.CSS_SELECTOR, "[type=submit]").click()
@ -163,7 +168,9 @@ class TestProviderSAML(SeleniumTestCase):
provider.property_mappings.set(SAMLPropertyMapping.objects.all()) provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save() provider.save()
Application.objects.create( Application.objects.create(
name="SAML", slug="passbook-saml", provider=provider, name="SAML",
slug="passbook-saml",
provider=provider,
) )
self.container = self.setup_client(provider) self.container = self.setup_client(provider)
self.driver.get( self.driver.get(
@ -209,7 +216,9 @@ class TestProviderSAML(SeleniumTestCase):
provider.property_mappings.set(SAMLPropertyMapping.objects.all()) provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save() provider.save()
app = Application.objects.create( app = Application.objects.create(
name="SAML", slug="passbook-saml", provider=provider, name="SAML",
slug="passbook-saml",
provider=provider,
) )
PolicyBinding.objects.create(target=app, policy=negative_policy, order=0) PolicyBinding.objects.create(target=app, policy=negative_policy, order=0)
self.container = self.setup_client(provider) self.container = self.setup_client(provider)

View file

@ -144,13 +144,15 @@ class TestSourceOAuth2(SeleniumTestCase):
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, "foo", self.driver.find_element(By.ID, "user-settings").text,
"foo",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_name").get_attribute("value"), "admin", self.driver.find_element(By.ID, "id_name").get_attribute("value"),
"admin",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_email").get_attribute("value"), self.driver.find_element(By.ID, "id_email").get_attribute("value"),
@ -225,13 +227,15 @@ class TestSourceOAuth2(SeleniumTestCase):
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, "foo", self.driver.find_element(By.ID, "user-settings").text,
"foo",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_name").get_attribute("value"), "admin", self.driver.find_element(By.ID, "id_name").get_attribute("value"),
"admin",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_email").get_attribute("value"), self.driver.find_element(By.ID, "id_email").get_attribute("value"),
@ -317,7 +321,8 @@ class TestSourceOAuth1(SeleniumTestCase):
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text, "example-user", self.driver.find_element(By.ID, "user-settings").text,
"example-user",
) )
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), self.driver.find_element(By.ID, "id_username").get_attribute("value"),

View file

@ -98,7 +98,9 @@ class TestSourceSAML(SeleniumTestCase):
authentication_flow = Flow.objects.get(slug="default-source-authentication") authentication_flow = Flow.objects.get(slug="default-source-authentication")
enrollment_flow = Flow.objects.get(slug="default-source-enrollment") enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
keypair = CertificateKeyPair.objects.create( keypair = CertificateKeyPair.objects.create(
name="test-idp-cert", certificate_data=IDP_CERT, key_data=IDP_KEY, name="test-idp-cert",
certificate_data=IDP_CERT,
key_data=IDP_KEY,
) )
SAMLSource.objects.create( SAMLSource.objects.create(
@ -145,7 +147,9 @@ class TestSourceSAML(SeleniumTestCase):
authentication_flow = Flow.objects.get(slug="default-source-authentication") authentication_flow = Flow.objects.get(slug="default-source-authentication")
enrollment_flow = Flow.objects.get(slug="default-source-enrollment") enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
keypair = CertificateKeyPair.objects.create( keypair = CertificateKeyPair.objects.create(
name="test-idp-cert", certificate_data=IDP_CERT, key_data=IDP_KEY, name="test-idp-cert",
certificate_data=IDP_CERT,
key_data=IDP_KEY,
) )
SAMLSource.objects.create( SAMLSource.objects.create(
@ -194,7 +198,9 @@ class TestSourceSAML(SeleniumTestCase):
authentication_flow = Flow.objects.get(slug="default-source-authentication") authentication_flow = Flow.objects.get(slug="default-source-authentication")
enrollment_flow = Flow.objects.get(slug="default-source-enrollment") enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
keypair = CertificateKeyPair.objects.create( keypair = CertificateKeyPair.objects.create(
name="test-idp-cert", certificate_data=IDP_CERT, key_data=IDP_KEY, name="test-idp-cert",
certificate_data=IDP_CERT,
key_data=IDP_KEY,
) )
SAMLSource.objects.create( SAMLSource.objects.create(

View file

@ -49,7 +49,9 @@ class YAMLField(forms.JSONField):
converted = yaml.safe_load(value) converted = yaml.safe_load(value)
except yaml.YAMLError: except yaml.YAMLError:
raise forms.ValidationError( raise forms.ValidationError(
self.error_messages["invalid"], code="invalid", params={"value": value}, self.error_messages["invalid"],
code="invalid",
params={"value": value},
) )
if isinstance(converted, str): if isinstance(converted, str):
return YAMLString(converted) return YAMLString(converted)

View file

@ -191,10 +191,20 @@ urlpatterns = [
), ),
# Flows # Flows
path("flows/", flows.FlowListView.as_view(), name="flows"), path("flows/", flows.FlowListView.as_view(), name="flows"),
path("flows/create/", flows.FlowCreateView.as_view(), name="flow-create",),
path("flows/import/", flows.FlowImportView.as_view(), name="flow-import",),
path( path(
"flows/<uuid:pk>/update/", flows.FlowUpdateView.as_view(), name="flow-update", "flows/create/",
flows.FlowCreateView.as_view(),
name="flow-create",
),
path(
"flows/import/",
flows.FlowImportView.as_view(),
name="flow-import",
),
path(
"flows/<uuid:pk>/update/",
flows.FlowUpdateView.as_view(),
name="flow-update",
), ),
path( path(
"flows/<uuid:pk>/execute/", "flows/<uuid:pk>/execute/",
@ -202,10 +212,14 @@ urlpatterns = [
name="flow-execute", name="flow-execute",
), ),
path( path(
"flows/<uuid:pk>/export/", flows.FlowExportView.as_view(), name="flow-export", "flows/<uuid:pk>/export/",
flows.FlowExportView.as_view(),
name="flow-export",
), ),
path( path(
"flows/<uuid:pk>/delete/", flows.FlowDeleteView.as_view(), name="flow-delete", "flows/<uuid:pk>/delete/",
flows.FlowDeleteView.as_view(),
name="flow-delete",
), ),
# Property Mappings # Property Mappings
path( path(
@ -273,9 +287,15 @@ urlpatterns = [
name="certificatekeypair-delete", name="certificatekeypair-delete",
), ),
# Outposts # Outposts
path("outposts/", outposts.OutpostListView.as_view(), name="outposts",),
path( path(
"outposts/create/", outposts.OutpostCreateView.as_view(), name="outpost-create", "outposts/",
outposts.OutpostListView.as_view(),
name="outposts",
),
path(
"outposts/create/",
outposts.OutpostCreateView.as_view(),
name="outpost-create",
), ),
path( path(
"outposts/<uuid:pk>/update/", "outposts/<uuid:pk>/update/",

View file

@ -100,7 +100,9 @@ class FlowDebugExecuteView(LoginRequiredMixin, PermissionRequiredMixin, DetailVi
plan = planner.plan(self.request, {PLAN_CONTEXT_PENDING_USER: request.user}) plan = planner.plan(self.request, {PLAN_CONTEXT_PENDING_USER: request.user})
self.request.session[SESSION_KEY_PLAN] = plan self.request.session[SESSION_KEY_PLAN] = plan
return redirect_with_qs( return redirect_with_qs(
"passbook_flows:flow-executor-shell", self.request.GET, flow_slug=flow.slug, "passbook_flows:flow-executor-shell",
self.request.GET,
flow_slug=flow.slug,
) )

View file

@ -114,7 +114,9 @@ info = openapi.Info(
license=openapi.License(name="MIT License"), license=openapi.License(name="MIT License"),
) )
SchemaView = get_schema_view( SchemaView = get_schema_view(
info, public=True, permission_classes=(CustomObjectPermissions,), info,
public=True,
permission_classes=(CustomObjectPermissions,),
) )
urlpatterns = [ urlpatterns = [

View file

@ -47,7 +47,10 @@ class Migration(migrations.Migration):
), ),
("date", models.DateTimeField(auto_now_add=True)), ("date", models.DateTimeField(auto_now_add=True)),
("app", models.TextField()), ("app", models.TextField()),
("context", models.JSONField(blank=True, default=dict),), (
"context",
models.JSONField(blank=True, default=dict),
),
("client_ip", models.GenericIPAddressField(null=True)), ("client_ip", models.GenericIPAddressField(null=True)),
("created", models.DateTimeField(auto_now_add=True)), ("created", models.DateTimeField(auto_now_add=True)),
( (

View file

@ -49,10 +49,15 @@ class Migration(migrations.Migration):
), ),
), ),
migrations.AddField( migrations.AddField(
model_name="event", name="user_json", field=models.JSONField(default=dict), model_name="event",
name="user_json",
field=models.JSONField(default=dict),
), ),
migrations.RunPython(convert_user_to_json), migrations.RunPython(convert_user_to_json),
migrations.RemoveField(model_name="event", name="user",), migrations.RemoveField(
model_name="event",
name="user",
),
migrations.RenameField( migrations.RenameField(
model_name="event", old_name="user_json", new_name="user" model_name="event", old_name="user_json", new_name="user"
), ),

View file

@ -108,11 +108,18 @@ class Migration(migrations.Migration):
("uuid", models.UUIDField(default=uuid.uuid4, editable=False)), ("uuid", models.UUIDField(default=uuid.uuid4, editable=False)),
("name", models.TextField(help_text="User's display name.")), ("name", models.TextField(help_text="User's display name.")),
("password_change_date", models.DateTimeField(auto_now_add=True)), ("password_change_date", models.DateTimeField(auto_now_add=True)),
("attributes", models.JSONField(blank=True, default=dict),), (
"attributes",
models.JSONField(blank=True, default=dict),
),
], ],
options={"permissions": (("reset_user_password", "Reset Password"),),}, options={
"permissions": (("reset_user_password", "Reset Password"),),
},
bases=(guardian.mixins.GuardianUserMixin, models.Model), bases=(guardian.mixins.GuardianUserMixin, models.Model),
managers=[("objects", django.contrib.auth.models.UserManager()),], managers=[
("objects", django.contrib.auth.models.UserManager()),
],
), ),
migrations.CreateModel( migrations.CreateModel(
name="PropertyMapping", name="PropertyMapping",
@ -192,7 +199,9 @@ class Migration(migrations.Migration):
), ),
), ),
], ],
options={"unique_together": {("user", "source")},}, options={
"unique_together": {("user", "source")},
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="Token", name="Token",
@ -223,7 +232,10 @@ class Migration(migrations.Migration):
), ),
), ),
], ],
options={"verbose_name": "Token", "verbose_name_plural": "Tokens",}, options={
"verbose_name": "Token",
"verbose_name_plural": "Tokens",
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="Provider", name="Provider",
@ -258,7 +270,10 @@ class Migration(migrations.Migration):
), ),
), ),
("name", models.CharField(max_length=80, verbose_name="name")), ("name", models.CharField(max_length=80, verbose_name="name")),
("attributes", models.JSONField(blank=True, default=dict),), (
"attributes",
models.JSONField(blank=True, default=dict),
),
( (
"parent", "parent",
models.ForeignKey( models.ForeignKey(
@ -270,7 +285,9 @@ class Migration(migrations.Migration):
), ),
), ),
], ],
options={"unique_together": {("name", "parent")},}, options={
"unique_together": {("name", "parent")},
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="Application", name="Application",

View file

@ -12,7 +12,10 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(model_name="application", name="skip_authorization",), migrations.RemoveField(
model_name="application",
name="skip_authorization",
),
migrations.AddField( migrations.AddField(
model_name="source", model_name="source",
name="authentication_flow", name="authentication_flow",

View file

@ -25,8 +25,14 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(model_name="user", name="is_superuser",), migrations.RemoveField(
migrations.RemoveField(model_name="user", name="is_staff",), model_name="user",
name="is_superuser",
),
migrations.RemoveField(
model_name="user",
name="is_staff",
),
migrations.RunPython(create_default_user), migrations.RunPython(create_default_user),
migrations.AddField( migrations.AddField(
model_name="user", model_name="user",

View file

@ -13,7 +13,10 @@ def create_default_admin_group(apps: Apps, schema_editor: BaseDatabaseSchemaEdit
# Creates a default admin group # Creates a default admin group
group, _ = Group.objects.using(db_alias).get_or_create( group, _ = Group.objects.using(db_alias).get_or_create(
is_superuser=True, defaults={"name": "passbook Admins",} is_superuser=True,
defaults={
"name": "passbook Admins",
},
) )
group.users.set(User.objects.filter(username="pbadmin")) group.users.set(User.objects.filter(username="pbadmin"))
group.save() group.save()
@ -26,8 +29,14 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(model_name="user", name="is_superuser",), migrations.RemoveField(
migrations.RemoveField(model_name="user", name="is_staff",), model_name="user",
name="is_superuser",
),
migrations.RemoveField(
model_name="user",
name="is_staff",
),
migrations.AlterField( migrations.AlterField(
model_name="user", model_name="user",
name="pb_groups", name="pb_groups",
@ -44,6 +53,9 @@ class Migration(migrations.Migration):
), ),
migrations.RunPython(create_default_admin_group), migrations.RunPython(create_default_admin_group),
migrations.AlterModelManagers( migrations.AlterModelManagers(
name="user", managers=[("objects", passbook.core.models.UserManager()),], name="user",
managers=[
("objects", passbook.core.models.UserManager()),
],
), ),
] ]

View file

@ -56,7 +56,12 @@ class Group(models.Model):
class Meta: class Meta:
unique_together = (("name", "parent",),) unique_together = (
(
"name",
"parent",
),
)
class UserManager(DjangoUserManager): class UserManager(DjangoUserManager):

View file

@ -30,9 +30,9 @@ def user_stages(context: RequestContext) -> List[UIUserSettings]:
def user_sources(context: RequestContext) -> List[UIUserSettings]: def user_sources(context: RequestContext) -> List[UIUserSettings]:
"""Return a list of all sources which are enabled for the user""" """Return a list of all sources which are enabled for the user"""
user = context.get("request").user user = context.get("request").user
_all_sources: Iterable[Source] = ( _all_sources: Iterable[Source] = Source.objects.filter(
Source.objects.filter(enabled=True).select_subclasses() enabled=True
) ).select_subclasses()
matching_sources: List[UIUserSettings] = [] matching_sources: List[UIUserSettings] = []
for source in _all_sources: for source in _all_sources:
user_settings = source.ui_user_settings user_settings = source.ui_user_settings

View file

@ -36,7 +36,8 @@ class CertificateBuilder:
x509.Name( x509.Name(
[ [
x509.NameAttribute( x509.NameAttribute(
NameOID.COMMON_NAME, "passbook Self-signed Certificate", NameOID.COMMON_NAME,
"passbook Self-signed Certificate",
), ),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "passbook"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "passbook"),
x509.NameAttribute( x509.NameAttribute(
@ -49,7 +50,8 @@ class CertificateBuilder:
x509.Name( x509.Name(
[ [
x509.NameAttribute( x509.NameAttribute(
NameOID.COMMON_NAME, "passbook Self-signed Certificate", NameOID.COMMON_NAME,
"passbook Self-signed Certificate",
), ),
] ]
) )

View file

@ -58,7 +58,9 @@ class Command(BaseCommand): # pragma: no cover
help="How many processes should be started.", help="How many processes should be started.",
) )
parser.add_argument( parser.add_argument(
"--csv", action="store_true", help="Output results as CSV", "--csv",
action="store_true",
help="Output results as CSV",
) )
def benchmark_flows(self, proc_count) -> str: def benchmark_flows(self, proc_count) -> str:

View file

@ -53,7 +53,10 @@ class Migration(migrations.Migration):
), ),
), ),
], ],
options={"verbose_name": "Flow", "verbose_name_plural": "Flows",}, options={
"verbose_name": "Flow",
"verbose_name_plural": "Flows",
},
bases=("passbook_policies.policybindingmodel",), bases=("passbook_policies.policybindingmodel",),
), ),
migrations.CreateModel( migrations.CreateModel(

View file

@ -21,13 +21,18 @@ class Migration(migrations.Migration):
}, },
), ),
migrations.RenameField( migrations.RenameField(
model_name="flowstagebinding", old_name="flow", new_name="target", model_name="flowstagebinding",
old_name="flow",
new_name="target",
), ),
migrations.RenameField( migrations.RenameField(
model_name="flow", old_name="pbm", new_name="policybindingmodel_ptr", model_name="flow",
old_name="pbm",
new_name="policybindingmodel_ptr",
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name="flowstagebinding", unique_together={("target", "stage", "order")}, name="flowstagebinding",
unique_together={("target", "stage", "order")},
), ),
migrations.AlterField( migrations.AlterField(
model_name="flow", model_name="flow",

View file

@ -42,16 +42,30 @@ def create_default_authentication_flow(
flow, _ = Flow.objects.using(db_alias).update_or_create( flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-authentication-flow", slug="default-authentication-flow",
designation=FlowDesignation.AUTHENTICATION, designation=FlowDesignation.AUTHENTICATION,
defaults={"name": "Welcome to passbook!",}, defaults={
"name": "Welcome to passbook!",
},
) )
FlowStageBinding.objects.using(db_alias).update_or_create( FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow, stage=identification_stage, defaults={"order": 0,}, target=flow,
stage=identification_stage,
defaults={
"order": 0,
},
) )
FlowStageBinding.objects.using(db_alias).update_or_create( FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow, stage=password_stage, defaults={"order": 1,}, target=flow,
stage=password_stage,
defaults={
"order": 1,
},
) )
FlowStageBinding.objects.using(db_alias).update_or_create( FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow, stage=login_stage, defaults={"order": 2,}, target=flow,
stage=login_stage,
defaults={
"order": 2,
},
) )
@ -70,12 +84,16 @@ def create_default_invalidation_flow(
flow, _ = Flow.objects.using(db_alias).update_or_create( flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-invalidation-flow", slug="default-invalidation-flow",
designation=FlowDesignation.INVALIDATION, designation=FlowDesignation.INVALIDATION,
defaults={"name": "Logout",}, defaults={
"name": "Logout",
},
) )
FlowStageBinding.objects.using(db_alias).update_or_create( FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow, target=flow,
stage=UserLogoutStage.objects.using(db_alias).first(), stage=UserLogoutStage.objects.using(db_alias).first(),
defaults={"order": 0,}, defaults={
"order": 0,
},
) )

View file

@ -44,7 +44,9 @@ def create_default_source_enrollment_flow(
flow, _ = Flow.objects.using(db_alias).update_or_create( flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-source-enrollment", slug="default-source-enrollment",
designation=FlowDesignation.ENROLLMENT, designation=FlowDesignation.ENROLLMENT,
defaults={"name": "Welcome to passbook!",}, defaults={
"name": "Welcome to passbook!",
},
) )
PolicyBinding.objects.using(db_alias).update_or_create( PolicyBinding.objects.using(db_alias).update_or_create(
policy=flow_policy, target=flow, defaults={"order": 0} policy=flow_policy, target=flow, defaults={"order": 0}
@ -114,14 +116,18 @@ def create_default_source_authentication_flow(
# Create a policy that only allows this flow when doing an SSO Request # Create a policy that only allows this flow when doing an SSO Request
flow_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create( flow_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create(
name="default-source-authentication-if-sso", name="default-source-authentication-if-sso",
defaults={"expression": FLOW_POLICY_EXPRESSION,}, defaults={
"expression": FLOW_POLICY_EXPRESSION,
},
) )
# This creates a Flow used by sources to authenticate users # This creates a Flow used by sources to authenticate users
flow, _ = Flow.objects.using(db_alias).update_or_create( flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-source-authentication", slug="default-source-authentication",
designation=FlowDesignation.AUTHENTICATION, designation=FlowDesignation.AUTHENTICATION,
defaults={"name": "Welcome to passbook!",}, defaults={
"name": "Welcome to passbook!",
},
) )
PolicyBinding.objects.using(db_alias).update_or_create( PolicyBinding.objects.using(db_alias).update_or_create(
policy=flow_policy, target=flow, defaults={"order": 0} policy=flow_policy, target=flow, defaults={"order": 0}

View file

@ -47,6 +47,8 @@ class Migration(migrations.Migration):
), ),
migrations.RunPython(add_title_for_defaults), migrations.RunPython(add_title_for_defaults),
migrations.AlterField( migrations.AlterField(
model_name="flow", name="title", field=models.TextField(), model_name="flow",
name="title",
field=models.TextField(),
), ),
] ]

View file

@ -21,6 +21,8 @@ class Migration(migrations.Migration):
), ),
), ),
migrations.AlterField( migrations.AlterField(
model_name="stage", name="name", field=models.TextField(unique=True), model_name="stage",
name="name",
field=models.TextField(unique=True),
), ),
] ]

View file

@ -177,6 +177,7 @@ class FlowPlanner:
marker = ReevaluateMarker(binding=binding, user=user) marker = ReevaluateMarker(binding=binding, user=user)
plan.markers.append(marker) plan.markers.append(marker)
LOGGER.debug( LOGGER.debug(
"f(plan): Finished building", flow=self.flow, "f(plan): Finished building",
flow=self.flow,
) )
return plan return plan

View file

@ -52,7 +52,8 @@ class TestFlowPlanner(TestCase):
planner.plan(request) planner.plan(request)
@patch( @patch(
"passbook.policies.engine.PolicyEngine.result", POLICY_RETURN_FALSE, "passbook.policies.engine.PolicyEngine.result",
POLICY_RETURN_FALSE,
) )
def test_non_applicable_plan(self): def test_non_applicable_plan(self):
"""Test that empty plan raises exception""" """Test that empty plan raises exception"""

View file

@ -39,7 +39,9 @@ class TestFlowTransfer(TransactionTestCase):
title=generate_client_id(), title=generate_client_id(),
) )
FlowStageBinding.objects.update_or_create( FlowStageBinding.objects.update_or_create(
target=flow, stage=login_stage, order=0, target=flow,
stage=login_stage,
order=0,
) )
exporter = FlowExporter(flow) exporter = FlowExporter(flow)
@ -59,7 +61,8 @@ class TestFlowTransfer(TransactionTestCase):
stage_name = generate_client_id() stage_name = generate_client_id()
with transaction_rollback(): with transaction_rollback():
flow_policy = ExpressionPolicy.objects.create( flow_policy = ExpressionPolicy.objects.create(
name=generate_client_id(), expression="return True", name=generate_client_id(),
expression="return True",
) )
flow = Flow.objects.create( flow = Flow.objects.create(
slug=flow_slug, slug=flow_slug,

View file

@ -63,10 +63,12 @@ class TestFlowExecutor(TestCase):
self.assertEqual(cancel_mock.call_count, 2) self.assertEqual(cancel_mock.call_count, 2)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
@patch( @patch(
"passbook.policies.engine.PolicyEngine.result", POLICY_RETURN_FALSE, "passbook.policies.engine.PolicyEngine.result",
POLICY_RETURN_FALSE,
) )
def test_invalid_non_applicable_flow(self): def test_invalid_non_applicable_flow(self):
"""Tests that a non-applicable flow returns the correct error message""" """Tests that a non-applicable flow returns the correct error message"""
@ -85,7 +87,8 @@ class TestFlowExecutor(TestCase):
self.assertInHTML(FlowNonApplicableException.__doc__, response.rendered_content) self.assertInHTML(FlowNonApplicableException.__doc__, response.rendered_content)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_invalid_empty_flow(self): def test_invalid_empty_flow(self):
"""Tests that an empty flow returns the correct error message""" """Tests that an empty flow returns the correct error message"""
@ -117,7 +120,8 @@ class TestFlowExecutor(TestCase):
response = self.client.get(url + f"?{NEXT_ARG_NAME}={dest}") response = self.client.get(url + f"?{NEXT_ARG_NAME}={dest}")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertJSONEqual( self.assertJSONEqual(
force_str(response.content), {"type": "redirect", "to": dest}, force_str(response.content),
{"type": "redirect", "to": dest},
) )
def test_multi_stage_flow(self): def test_multi_stage_flow(self):

View file

@ -15,8 +15,12 @@ class TestHelperView(TestCase):
def test_default_view(self): def test_default_view(self):
"""Test that ToDefaultFlow returns the expected URL""" """Test that ToDefaultFlow returns the expected URL"""
flow = Flow.objects.filter(designation=FlowDesignation.INVALIDATION,).first() flow = Flow.objects.filter(
response = self.client.get(reverse("passbook_flows:default-invalidation"),) designation=FlowDesignation.INVALIDATION,
).first()
response = self.client.get(
reverse("passbook_flows:default-invalidation"),
)
expected_url = reverse( expected_url = reverse(
"passbook_flows:flow-executor-shell", kwargs={"flow_slug": flow.slug} "passbook_flows:flow-executor-shell", kwargs={"flow_slug": flow.slug}
) )
@ -25,13 +29,17 @@ class TestHelperView(TestCase):
def test_default_view_invalid_plan(self): def test_default_view_invalid_plan(self):
"""Test that ToDefaultFlow returns the expected URL (with an invalid plan)""" """Test that ToDefaultFlow returns the expected URL (with an invalid plan)"""
flow = Flow.objects.filter(designation=FlowDesignation.INVALIDATION,).first() flow = Flow.objects.filter(
designation=FlowDesignation.INVALIDATION,
).first()
plan = FlowPlan(flow_pk=flow.pk.hex + "aa") plan = FlowPlan(flow_pk=flow.pk.hex + "aa")
session = self.client.session session = self.client.session
session[SESSION_KEY_PLAN] = plan session[SESSION_KEY_PLAN] = plan
session.save() session.save()
response = self.client.get(reverse("passbook_flows:default-invalidation"),) response = self.client.get(
reverse("passbook_flows:default-invalidation"),
)
expected_url = reverse( expected_url = reverse(
"passbook_flows:flow-executor-shell", kwargs={"flow_slug": flow.slug} "passbook_flows:flow-executor-shell", kwargs={"flow_slug": flow.slug}
) )

View file

@ -103,7 +103,9 @@ class BaseEvaluator:
param_keys = self._context.keys() param_keys = self._context.keys()
try: try:
compile( compile(
self.wrap_expression(expression, param_keys), self._filename, "exec", self.wrap_expression(expression, param_keys),
self._filename,
"exec",
) )
return True return True
except (ValueError, SyntaxError) as exc: except (ValueError, SyntaxError) as exc:

View file

@ -71,7 +71,14 @@ def gravatar(email, size=None, rating=None):
md5(email.encode("utf-8")).hexdigest(), # nosec md5(email.encode("utf-8")).hexdigest(), # nosec
) )
parameters = [p for p in (("s", size or "158"), ("r", rating or "g"),) if p[1]] parameters = [
p
for p in (
("s", size or "158"),
("r", rating or "g"),
)
if p[1]
]
if parameters: if parameters:
gravatar_url += "?" + urlencode(parameters, doseq=True) gravatar_url += "?" + urlencode(parameters, doseq=True)

View file

@ -34,5 +34,8 @@ def bad_request_message(
) -> TemplateResponse: ) -> TemplateResponse:
"""Return generic error page with message, with status code set to 400""" """Return generic error page with message, with status code set to 400"""
return TemplateResponse( return TemplateResponse(
request, template, {"message": message, "card_title": _(title)}, status=400, request,
template,
{"message": message, "card_title": _(title)},
status=400,
) )

View file

@ -29,7 +29,9 @@ class DockerComposeView(LoginRequiredMixin, View):
def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse: def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse:
"""Render docker-compose file""" """Render docker-compose file"""
outpost: Outpost = get_object_for_user_or_404( outpost: Outpost = get_object_for_user_or_404(
request.user, "passbook_outposts.view_outpost", pk=outpost_pk, request.user,
"passbook_outposts.view_outpost",
pk=outpost_pk,
) )
manifest = "" manifest = ""
if outpost.type == OutpostType.PROXY: if outpost.type == OutpostType.PROXY:
@ -45,7 +47,9 @@ class KubernetesManifestView(LoginRequiredMixin, View):
def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse: def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse:
"""Render deployment template""" """Render deployment template"""
outpost: Outpost = get_object_for_user_or_404( outpost: Outpost = get_object_for_user_or_404(
request.user, "passbook_outposts.view_outpost", pk=outpost_pk, request.user,
"passbook_outposts.view_outpost",
pk=outpost_pk,
) )
manifest = "" manifest = ""
if outpost.type == OutpostType.PROXY: if outpost.type == OutpostType.PROXY:

View file

@ -47,7 +47,8 @@ class PolicyBindingSerializer(ModelSerializer):
# Because we're not interested in the PolicyBindingModel's PK but rather the subclasses PK, # Because we're not interested in the PolicyBindingModel's PK but rather the subclasses PK,
# we have to manually declare this field # we have to manually declare this field
target = PolicyBindingModelForeignKey( target = PolicyBindingModelForeignKey(
queryset=PolicyBindingModel.objects.select_subclasses(), required=True, queryset=PolicyBindingModel.objects.select_subclasses(),
required=True,
) )
class Meta: class Meta:

View file

@ -16,7 +16,9 @@ class PolicyBindingForm(forms.ModelForm):
queryset=PolicyBindingModel.objects.all().select_subclasses(), queryset=PolicyBindingModel.objects.all().select_subclasses(),
to_field_name="pbm_uuid", to_field_name="pbm_uuid",
) )
policy = GroupedModelChoiceField(queryset=Policy.objects.all().select_subclasses(),) policy = GroupedModelChoiceField(
queryset=Policy.objects.all().select_subclasses(),
)
class Meta: class Meta:

View file

@ -12,7 +12,9 @@ class TestHIBPPolicy(TestCase):
def test_false(self): def test_false(self):
"""Failing password case""" """Failing password case"""
policy = HaveIBeenPwendPolicy.objects.create(name="test_false",) policy = HaveIBeenPwendPolicy.objects.create(
name="test_false",
)
request = PolicyRequest(get_anonymous_user()) request = PolicyRequest(get_anonymous_user())
request.context["password"] = "password" request.context["password"] = "password"
result: PolicyResult = policy.passes(request) result: PolicyResult = policy.passes(request)
@ -21,7 +23,9 @@ class TestHIBPPolicy(TestCase):
def test_true(self): def test_true(self):
"""Positive password case""" """Positive password case"""
policy = HaveIBeenPwendPolicy.objects.create(name="test_true",) policy = HaveIBeenPwendPolicy.objects.create(
name="test_true",
)
request = PolicyRequest(get_anonymous_user()) request = PolicyRequest(get_anonymous_user())
request.context["password"] = generate_client_secret() request.context["password"] = generate_client_secret()
result: PolicyResult = policy.passes(request) result: PolicyResult = policy.passes(request)

View file

@ -32,7 +32,9 @@ class Migration(migrations.Migration):
("order", models.IntegerField(default=0)), ("order", models.IntegerField(default=0)),
("timeout", models.IntegerField(default=30)), ("timeout", models.IntegerField(default=30)),
], ],
options={"abstract": False,}, options={
"abstract": False,
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="PolicyBinding", name="PolicyBinding",

View file

@ -21,9 +21,18 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Policies", "verbose_name_plural": "Policies",
}, },
), ),
migrations.RemoveField(model_name="policy", name="negate",), migrations.RemoveField(
migrations.RemoveField(model_name="policy", name="order",), model_name="policy",
migrations.RemoveField(model_name="policy", name="timeout",), name="negate",
),
migrations.RemoveField(
model_name="policy",
name="order",
),
migrations.RemoveField(
model_name="policy",
name="timeout",
),
migrations.AddField( migrations.AddField(
model_name="policybinding", model_name="policybinding",
name="negate", name="negate",
@ -41,7 +50,9 @@ class Migration(migrations.Migration):
), ),
), ),
migrations.AlterField( migrations.AlterField(
model_name="policybinding", name="order", field=models.IntegerField(), model_name="policybinding",
name="order",
field=models.IntegerField(),
), ),
migrations.AlterField( migrations.AlterField(
model_name="policybinding", model_name="policybinding",
@ -53,6 +64,7 @@ class Migration(migrations.Migration):
), ),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name="policybinding", unique_together={("policy", "target", "order")}, name="policybinding",
unique_together={("policy", "target", "order")},
), ),
] ]

View file

@ -73,7 +73,10 @@ class PolicyAccessMixin(BaseMixin, AccessMixin):
policy_engine.build() policy_engine.build()
result = policy_engine.result result = policy_engine.result
LOGGER.debug( LOGGER.debug(
"AccessMixin user_has_access", user=user, app=application, result=result, "AccessMixin user_has_access",
user=user,
app=application,
result=result,
) )
if not result.passing: if not result.passing:
for message in result.messages: for message in result.messages:

View file

@ -48,7 +48,9 @@ class PolicyProcess(Process):
def execute(self) -> PolicyResult: def execute(self) -> PolicyResult:
"""Run actual policy, returns result""" """Run actual policy, returns result"""
with Hub.current.start_span(op="policy.process.execute",) as span: with Hub.current.start_span(
op="policy.process.execute",
) as span:
span: Span span: Span
span.set_data("policy", self.binding.policy) span.set_data("policy", self.binding.policy)
span.set_data("request", self.request) span.set_data("request", self.request)

View file

@ -283,7 +283,10 @@ class Migration(migrations.Migration):
), ),
), ),
], ],
options={"verbose_name": "Token", "verbose_name_plural": "Tokens",}, options={
"verbose_name": "Token",
"verbose_name_plural": "Tokens",
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="AuthorizationCode", name="AuthorizationCode",

View file

@ -11,6 +11,7 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(
model_name="oauth2provider", name="post_logout_redirect_uris", model_name="oauth2provider",
name="post_logout_redirect_uris",
), ),
] ]

View file

@ -292,13 +292,19 @@ class OAuth2Provider(Provider):
"provider": self, "provider": self,
"issuer": self.get_issuer(request), "issuer": self.get_issuer(request),
"authorize": request.build_absolute_uri( "authorize": request.build_absolute_uri(
reverse("passbook_providers_oauth2:authorize",) reverse(
"passbook_providers_oauth2:authorize",
)
), ),
"token": request.build_absolute_uri( "token": request.build_absolute_uri(
reverse("passbook_providers_oauth2:token",) reverse(
"passbook_providers_oauth2:token",
)
), ),
"userinfo": request.build_absolute_uri( "userinfo": request.build_absolute_uri(
reverse("passbook_providers_oauth2:userinfo",) reverse(
"passbook_providers_oauth2:userinfo",
)
), ),
"provider_info": request.build_absolute_uri( "provider_info": request.build_absolute_uri(
reverse( reverse(

View file

@ -13,7 +13,11 @@ from passbook.providers.oauth2.views.token import TokenView
from passbook.providers.oauth2.views.userinfo import UserInfoView from passbook.providers.oauth2.views.userinfo import UserInfoView
urlpatterns = [ urlpatterns = [
path("authorize/", AuthorizationFlowInitView.as_view(), name="authorize",), path(
"authorize/",
AuthorizationFlowInitView.as_view(),
name="authorize",
),
path("token/", csrf_exempt(TokenView.as_view()), name="token"), path("token/", csrf_exempt(TokenView.as_view()), name="token"),
path( path(
"userinfo/", "userinfo/",

View file

@ -257,7 +257,8 @@ class OAuthFulfillmentStage(StageView):
] ]
elif self.params.grant_type in [GrantTypes.IMPLICIT, GrantTypes.HYBRID]: elif self.params.grant_type in [GrantTypes.IMPLICIT, GrantTypes.HYBRID]:
token = self.provider.create_refresh_token( token = self.provider.create_refresh_token(
user=self.request.user, scope=self.params.scope, user=self.request.user,
scope=self.params.scope,
) )
# Check if response_type must include access_token in the response. # Check if response_type must include access_token in the response.
@ -272,7 +273,8 @@ class OAuthFulfillmentStage(StageView):
# We don't need id_token if it's an OAuth2 request. # We don't need id_token if it's an OAuth2 request.
if SCOPE_OPENID in self.params.scope: if SCOPE_OPENID in self.params.scope:
id_token = token.create_id_token( id_token = token.create_id_token(
user=self.request.user, request=self.request, user=self.request.user,
request=self.request,
) )
id_token.nonce = self.params.nonce id_token.nonce = self.params.nonce

View file

@ -35,7 +35,8 @@ class TokenIntrospectionParams:
if not self.token.id_token: if not self.token.id_token:
LOGGER.debug( LOGGER.debug(
"token not an authentication token", token=self.token, "token not an authentication token",
token=self.token,
) )
raise TokenIntrospectionError() raise TokenIntrospectionError()

View file

@ -96,7 +96,8 @@ class TokenParams:
except RefreshToken.DoesNotExist: except RefreshToken.DoesNotExist:
LOGGER.warning( LOGGER.warning(
"Refresh token does not exist", token=raw_token, "Refresh token does not exist",
token=raw_token,
) )
raise TokenError("invalid_grant") raise TokenError("invalid_grant")
@ -178,7 +179,8 @@ class TokenView(View):
if self.params.authorization_code.is_open_id: if self.params.authorization_code.is_open_id:
id_token = refresh_token.create_id_token( id_token = refresh_token.create_id_token(
user=self.params.authorization_code.user, request=self.request, user=self.params.authorization_code.user,
request=self.request,
) )
id_token.nonce = self.params.authorization_code.nonce id_token.nonce = self.params.authorization_code.nonce
id_token.at_hash = refresh_token.at_hash id_token.at_hash = refresh_token.at_hash
@ -221,13 +223,15 @@ class TokenView(View):
provider: OAuth2Provider = self.params.refresh_token.provider provider: OAuth2Provider = self.params.refresh_token.provider
refresh_token: RefreshToken = provider.create_refresh_token( refresh_token: RefreshToken = provider.create_refresh_token(
user=self.params.refresh_token.user, scope=self.params.scope, user=self.params.refresh_token.user,
scope=self.params.scope,
) )
# If the Token has an id_token it's an Authentication request. # If the Token has an id_token it's an Authentication request.
if self.params.refresh_token.id_token: if self.params.refresh_token.id_token:
refresh_token.id_token = refresh_token.create_id_token( refresh_token.id_token = refresh_token.create_id_token(
user=self.params.refresh_token.user, request=self.request, user=self.params.refresh_token.user,
request=self.request,
) )
refresh_token.id_token.at_hash = refresh_token.at_hash refresh_token.id_token.at_hash = refresh_token.at_hash

View file

@ -92,7 +92,10 @@ class ProxyProvider(OutpostModel, OAuth2Provider):
) )
certificate = models.ForeignKey( certificate = models.ForeignKey(
CertificateKeyPair, on_delete=models.SET_NULL, null=True, blank=True, CertificateKeyPair,
on_delete=models.SET_NULL,
null=True,
blank=True,
) )
cookie_secret = models.TextField(default=get_cookie_secret) cookie_secret = models.TextField(default=get_cookie_secret)

View file

@ -10,5 +10,8 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(model_name="samlprovider", name="processor_path",), migrations.RemoveField(
model_name="samlprovider",
name="processor_path",
),
] ]

View file

@ -72,7 +72,10 @@ class SAMLProvider(Provider):
digest_algorithm = models.CharField( digest_algorithm = models.CharField(
max_length=50, max_length=50,
choices=(("sha1", _("SHA1")), ("sha256", _("SHA256")),), choices=(
("sha1", _("SHA1")),
("sha256", _("SHA256")),
),
default="sha256", default="sha256",
) )
signature_algorithm = models.CharField( signature_algorithm = models.CharField(

View file

@ -47,7 +47,7 @@ SESSION_KEY_AUTH_N_REQUEST = "authn_request"
class SAMLSSOView(PolicyAccessMixin, View): class SAMLSSOView(PolicyAccessMixin, View):
""""SAML SSO Base View, which plans a flow and injects our final stage. """ "SAML SSO Base View, which plans a flow and injects our final stage.
Calls get/post handler.""" Calls get/post handler."""
application: Application application: Application

View file

@ -38,7 +38,11 @@ for _passbook_app in get_apps():
for module, mountpoint in mountpoints.items(): for module, mountpoint in mountpoints.items():
namespace = _passbook_app.label + module.replace(base_url_module, "") namespace = _passbook_app.label + module.replace(base_url_module, "")
_path = path( _path = path(
mountpoint, include((module, _passbook_app.label), namespace=namespace,), mountpoint,
include(
(module, _passbook_app.label),
namespace=namespace,
),
) )
urlpatterns.append(_path) urlpatterns.append(_path)
LOGGER.debug( LOGGER.debug(

View file

@ -91,7 +91,8 @@ class LDAPSynchronizer:
try: try:
defaults = self._build_object_properties(attributes) defaults = self._build_object_properties(attributes)
user, created = User.objects.update_or_create( user, created = User.objects.update_or_create(
attributes__ldap_uniq=uniq, defaults=defaults, attributes__ldap_uniq=uniq,
defaults=defaults,
) )
except IntegrityError as exc: except IntegrityError as exc:
LOGGER.warning("Failed to create user", exc=exc) LOGGER.warning("Failed to create user", exc=exc)

View file

@ -69,7 +69,8 @@ class OAuthSource(Source):
def ui_user_settings(self) -> Optional[UIUserSettings]: def ui_user_settings(self) -> Optional[UIUserSettings]:
view_name = "passbook_sources_oauth:oauth-client-user" view_name = "passbook_sources_oauth:oauth-client-user"
return UIUserSettings( return UIUserSettings(
name=self.name, url=reverse(view_name, kwargs={"source_slug": self.slug}), name=self.name,
url=reverse(view_name, kwargs={"source_slug": self.slug}),
) )
def __str__(self) -> str: def __str__(self) -> str:

View file

@ -147,7 +147,9 @@ class OAuthCallback(OAuthClientMixin, View):
plan = planner.plan(self.request, kwargs) plan = planner.plan(self.request, kwargs)
self.request.session[SESSION_KEY_PLAN] = plan self.request.session[SESSION_KEY_PLAN] = plan
return redirect_with_qs( return redirect_with_qs(
"passbook_flows:flow-executor-shell", self.request.GET, flow_slug=flow.slug, "passbook_flows:flow-executor-shell",
self.request.GET,
flow_slug=flow.slug,
) )
# pylint: disable=unused-argument # pylint: disable=unused-argument

View file

@ -21,7 +21,8 @@ class SAMLSourceForm(forms.ModelForm):
designation=FlowDesignation.ENROLLMENT designation=FlowDesignation.ENROLLMENT
) )
self.fields["signing_kp"].queryset = CertificateKeyPair.objects.filter( self.fields["signing_kp"].queryset = CertificateKeyPair.objects.filter(
certificate_data__isnull=False, key_data__isnull=False, certificate_data__isnull=False,
key_data__isnull=False,
) )
class Meta: class Meta:

View file

@ -14,12 +14,19 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(model_name="samlsource", name="auto_logout",), migrations.RemoveField(
migrations.RenameField( model_name="samlsource",
model_name="samlsource", old_name="idp_url", new_name="sso_url", name="auto_logout",
), ),
migrations.RenameField( migrations.RenameField(
model_name="samlsource", old_name="idp_logout_url", new_name="slo_url", model_name="samlsource",
old_name="idp_url",
new_name="sso_url",
),
migrations.RenameField(
model_name="samlsource",
old_name="idp_logout_url",
new_name="slo_url",
), ),
migrations.AddField( migrations.AddField(
model_name="samlsource", model_name="samlsource",

View file

@ -191,5 +191,7 @@ class ResponseProcessor:
kwargs[PLAN_CONTEXT_SSO] = True kwargs[PLAN_CONTEXT_SSO] = True
request.session[SESSION_KEY_PLAN] = FlowPlanner(flow).plan(request, kwargs) request.session[SESSION_KEY_PLAN] = FlowPlanner(flow).plan(request, kwargs)
return redirect_with_qs( return redirect_with_qs(
"passbook_flows:flow-executor-shell", request.GET, flow_slug=flow.slug, "passbook_flows:flow-executor-shell",
request.GET,
flow_slug=flow.slug,
) )

View file

@ -23,7 +23,8 @@ class TestConsentStage(TestCase):
username="unittest", email="test@beryju.org" username="unittest", email="test@beryju.org"
) )
self.application = Application.objects.create( self.application = Application.objects.create(
name="test-application", slug="test-application", name="test-application",
slug="test-application",
) )
self.client = Client() self.client = Client()

View file

@ -22,9 +22,13 @@ class TestDummyStage(TestCase):
slug="test-dummy", slug="test-dummy",
designation=FlowDesignation.AUTHENTICATION, designation=FlowDesignation.AUTHENTICATION,
) )
self.stage = DummyStage.objects.create(name="dummy",) self.stage = DummyStage.objects.create(
name="dummy",
)
FlowStageBinding.objects.create( FlowStageBinding.objects.create(
target=self.flow, stage=self.stage, order=0, target=self.flow,
stage=self.stage,
order=0,
) )
def test_valid_render(self): def test_valid_render(self):

View file

@ -23,7 +23,12 @@ def send_mails(stage: EmailStage, *messages: List[EmailMultiAlternatives]):
@CELERY_APP.task( @CELERY_APP.task(
bind=True, autoretry_for=(SMTPException, ConnectionError,), retry_backoff=True bind=True,
autoretry_for=(
SMTPException,
ConnectionError,
),
retry_backoff=True,
) )
# pylint: disable=unused-argument # pylint: disable=unused-argument
def _send_mail_task(self, email_stage_pk: int, message: Dict[Any, Any]): def _send_mail_task(self, email_stage_pk: int, message: Dict[Any, Any]):

View file

@ -30,7 +30,9 @@ class TestEmailStage(TestCase):
slug="test-email", slug="test-email",
designation=FlowDesignation.AUTHENTICATION, designation=FlowDesignation.AUTHENTICATION,
) )
self.stage = EmailStage.objects.create(name="email",) self.stage = EmailStage.objects.create(
name="email",
)
FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2) FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
def test_rendering(self): def test_rendering(self):

View file

@ -32,7 +32,9 @@ class TestIdentificationStage(TestCase):
template=Templates.DEFAULT_LOGIN, template=Templates.DEFAULT_LOGIN,
) )
FlowStageBinding.objects.create( FlowStageBinding.objects.create(
target=self.flow, stage=self.stage, order=0, target=self.flow,
stage=self.stage,
order=0,
) )
# OAuthSource for the login view # OAuthSource for the login view
@ -92,7 +94,9 @@ class TestIdentificationStage(TestCase):
self.stage.enrollment_flow = flow self.stage.enrollment_flow = flow
self.stage.save() self.stage.save()
FlowStageBinding.objects.create( FlowStageBinding.objects.create(
target=flow, stage=self.stage, order=0, target=flow,
stage=self.stage,
order=0,
) )
response = self.client.get( response = self.client.get(
@ -113,7 +117,9 @@ class TestIdentificationStage(TestCase):
self.stage.recovery_flow = flow self.stage.recovery_flow = flow
self.stage.save() self.stage.save()
FlowStageBinding.objects.create( FlowStageBinding.objects.create(
target=flow, stage=self.stage, order=0, target=flow,
stage=self.stage,
order=0,
) )
response = self.client.get( response = self.client.get(

View file

@ -58,7 +58,10 @@ class Migration(migrations.Migration):
), ),
), ),
("expires", models.DateTimeField(blank=True, default=None, null=True)), ("expires", models.DateTimeField(blank=True, default=None, null=True)),
("fixed_data", models.JSONField(default=dict),), (
"fixed_data",
models.JSONField(default=dict),
),
( (
"created_by", "created_by",
models.ForeignKey( models.ForeignKey(

View file

@ -41,7 +41,8 @@ class TestUserLoginStage(TestCase):
self.assertEqual(InvitationStageForm(data).is_valid(), True) self.assertEqual(InvitationStageForm(data).is_valid(), True)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_without_invitation_fail(self): def test_without_invitation_fail(self):
"""Test without any invitation, continue_flow_without_invitation not set.""" """Test without any invitation, continue_flow_without_invitation not set."""

View file

@ -14,7 +14,10 @@ def get_authentication_backends():
"django.contrib.auth.backends.ModelBackend", "django.contrib.auth.backends.ModelBackend",
_("passbook-internal Userdatabase"), _("passbook-internal Userdatabase"),
), ),
("passbook.sources.ldap.auth.LDAPBackend", _("passbook LDAP"),), (
"passbook.sources.ldap.auth.LDAPBackend",
_("passbook LDAP"),
),
] ]

View file

@ -71,7 +71,8 @@ def update_default_stage_change(apps: Apps, schema_editor: BaseDatabaseSchemaEdi
Flow = apps.get_model("passbook_flows", "Flow") Flow = apps.get_model("passbook_flows", "Flow")
flow = Flow.objects.get( flow = Flow.objects.get(
slug="default-password-change", designation=FlowDesignation.STAGE_CONFIGURATION, slug="default-password-change",
designation=FlowDesignation.STAGE_CONFIGURATION,
) )
stages = PasswordStage.objects.filter(name="default-authentication-password") stages = PasswordStage.objects.filter(name="default-authentication-password")

View file

@ -45,7 +45,8 @@ class TestPasswordStage(TestCase):
FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2) FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_without_user(self): def test_without_user(self):
"""Test without user""" """Test without user"""
@ -163,7 +164,8 @@ class TestPasswordStage(TestCase):
self.assertNotIn(SESSION_KEY_PLAN, self.client.session) self.assertNotIn(SESSION_KEY_PLAN, self.client.session)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
@patch( @patch(
"django.contrib.auth.backends.ModelBackend.authenticate", "django.contrib.auth.backends.ModelBackend.authenticate",

View file

@ -65,7 +65,9 @@ class ListPolicyEngine(PolicyEngine):
def _iter_bindings(self) -> Iterator[PolicyBinding]: def _iter_bindings(self) -> Iterator[PolicyBinding]:
for policy in self.__list: for policy in self.__list:
yield PolicyBinding(policy=policy,) yield PolicyBinding(
policy=policy,
)
class PromptForm(forms.Form): class PromptForm(forms.Form):

View file

@ -64,7 +64,10 @@ class Migration(migrations.Migration):
("placeholder", models.TextField(blank=True)), ("placeholder", models.TextField(blank=True)),
("order", models.IntegerField(default=0)), ("order", models.IntegerField(default=0)),
], ],
options={"verbose_name": "Prompt", "verbose_name_plural": "Prompts",}, options={
"verbose_name": "Prompt",
"verbose_name_plural": "Prompts",
},
), ),
migrations.CreateModel( migrations.CreateModel(
name="PromptStage", name="PromptStage",

View file

@ -33,7 +33,8 @@ class TestUserDeleteStage(TestCase):
FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2) FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_no_user(self): def test_no_user(self):
"""Test without user set""" """Test without user set"""

View file

@ -59,7 +59,8 @@ class TestUserLoginStage(TestCase):
) )
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_without_user(self): def test_without_user(self):
"""Test a plan without any pending user, resulting in a denied""" """Test a plan without any pending user, resulting in a denied"""
@ -80,7 +81,8 @@ class TestUserLoginStage(TestCase):
self.assertIsInstance(response, AccessDeniedResponse) self.assertIsInstance(response, AccessDeniedResponse)
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_without_backend(self): def test_without_backend(self):
"""Test a plan with pending user, without backend, resulting in a denied""" """Test a plan with pending user, without backend, resulting in a denied"""

View file

@ -13,7 +13,9 @@ class UserLogoutStageView(StageView):
def get(self, request: HttpRequest) -> HttpResponse: def get(self, request: HttpRequest) -> HttpResponse:
LOGGER.debug( LOGGER.debug(
"Logged out", user=request.user, flow_slug=self.executor.flow.slug, "Logged out",
user=request.user,
flow_slug=self.executor.flow.slug,
) )
logout(self.request) logout(self.request)
return self.executor.stage_ok() return self.executor.stage_ok()

View file

@ -33,7 +33,8 @@ class UserWriteStageView(StageView):
PLAN_CONTEXT_AUTHENTICATION_BACKEND PLAN_CONTEXT_AUTHENTICATION_BACKEND
] = class_to_path(ModelBackend) ] = class_to_path(ModelBackend)
LOGGER.debug( LOGGER.debug(
"Created new user", flow_slug=self.executor.flow.slug, "Created new user",
flow_slug=self.executor.flow.slug,
) )
user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
# Before we change anything, check if the user is the same as in the request # Before we change anything, check if the user is the same as in the request
@ -68,6 +69,8 @@ class UserWriteStageView(StageView):
update_session_auth_hash(self.request, user) update_session_auth_hash(self.request, user)
LOGGER.debug("Updated session hash", user=user) LOGGER.debug("Updated session hash", user=user)
LOGGER.debug( LOGGER.debug(
"Updated existing user", user=user, flow_slug=self.executor.flow.slug, "Updated existing user",
user=user,
flow_slug=self.executor.flow.slug,
) )
return self.executor.stage_ok() return self.executor.stage_ok()

View file

@ -111,7 +111,8 @@ class TestUserWriteStage(TestCase):
self.assertEqual(user_qs.first().attributes["some-custom-attribute"], "test") self.assertEqual(user_qs.first().attributes["some-custom-attribute"], "test")
@patch( @patch(
"passbook.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, "passbook.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
) )
def test_without_data(self): def test_without_data(self):
"""Test without data results in error""" """Test without data results in error"""