*: apply new black styling
This commit is contained in:
parent
9ef39f1e04
commit
525d271535
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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/",
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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)),
|
||||||
(
|
(
|
||||||
|
|
|
@ -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"
|
||||||
),
|
),
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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()),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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(),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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}
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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")},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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/",
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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]):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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."""
|
||||||
|
|
|
@ -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"),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
Reference in a new issue