stages/password: assign default password change flow to password stage
add e2e tests for password change flow
This commit is contained in:
parent
96a6ac85df
commit
8d31eef47d
|
@ -286,6 +286,204 @@
|
||||||
],
|
],
|
||||||
"value": "foo@bar.baz"
|
"value": "foo@bar.baz"
|
||||||
}]
|
}]
|
||||||
|
}, {
|
||||||
|
"id": "1a3172e0-ac23-4781-9367-19afccee4f4a",
|
||||||
|
"name": "flows stage setup password",
|
||||||
|
"commands": [{
|
||||||
|
"id": "77784f77-d840-4b3d-a42f-7928f02fb7e1",
|
||||||
|
"comment": "",
|
||||||
|
"command": "open",
|
||||||
|
"target": "/flows/default-authentication-flow/?next=%2F",
|
||||||
|
"targets": [],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "783aa9a6-81e5-49c6-8789-2f360a5750b1",
|
||||||
|
"comment": "",
|
||||||
|
"command": "setWindowSize",
|
||||||
|
"target": "1699x1417",
|
||||||
|
"targets": [],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "cb0cd63e-30e9-4443-af59-5345fe26dc88",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "id=id_uid_field",
|
||||||
|
"targets": [
|
||||||
|
["id=id_uid_field", "id"],
|
||||||
|
["name=uid_field", "name"],
|
||||||
|
["css=#id_uid_field", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_uid_field']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "8466ded1-c5f6-451c-b63f-0889da38503a",
|
||||||
|
"comment": "",
|
||||||
|
"command": "type",
|
||||||
|
"target": "id=id_uid_field",
|
||||||
|
"targets": [
|
||||||
|
["id=id_uid_field", "id"],
|
||||||
|
["name=uid_field", "name"],
|
||||||
|
["css=#id_uid_field", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_uid_field']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "pbadmin"
|
||||||
|
}, {
|
||||||
|
"id": "27383093-d01a-4416-8fc6-9caad4926cd3",
|
||||||
|
"comment": "",
|
||||||
|
"command": "sendKeys",
|
||||||
|
"target": "id=id_uid_field",
|
||||||
|
"targets": [
|
||||||
|
["id=id_uid_field", "id"],
|
||||||
|
["name=uid_field", "name"],
|
||||||
|
["css=#id_uid_field", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_uid_field']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "${KEY_ENTER}"
|
||||||
|
}, {
|
||||||
|
"id": "4602745a-0ebb-4425-a841-a1ed4899659d",
|
||||||
|
"comment": "",
|
||||||
|
"command": "type",
|
||||||
|
"target": "id=id_password",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password", "id"],
|
||||||
|
["name=password", "name"],
|
||||||
|
["css=#id_password", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div[2]/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div[2]/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "pbadmin"
|
||||||
|
}, {
|
||||||
|
"id": "d1ff4f81-d8f9-45dc-ad5d-f99b54c0cd18",
|
||||||
|
"comment": "",
|
||||||
|
"command": "sendKeys",
|
||||||
|
"target": "id=id_password",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password", "id"],
|
||||||
|
["name=password", "name"],
|
||||||
|
["css=#id_password", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div[2]/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div[2]/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "${KEY_ENTER}"
|
||||||
|
}, {
|
||||||
|
"id": "014c8f57-7ef2-469c-b700-efa94ba81b66",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "css=.pf-c-page__header",
|
||||||
|
"targets": [
|
||||||
|
["css=.pf-c-page__header", "css:finder"],
|
||||||
|
["xpath=//div[@id='page-default-nav-example']/header", "xpath:idRelative"],
|
||||||
|
["xpath=//header", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "14e86b6f-6add-4bcc-913a-42b1e7322c79",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "linkText=pbadmin",
|
||||||
|
"targets": [
|
||||||
|
["linkText=pbadmin", "linkText"],
|
||||||
|
["css=.pf-c-page__header-tools-group:nth-child(2) > .pf-c-button", "css:finder"],
|
||||||
|
["xpath=//a[contains(text(),'pbadmin')]", "xpath:link"],
|
||||||
|
["xpath=//div[@id='page-default-nav-example']/header/div[3]/div[2]/a", "xpath:idRelative"],
|
||||||
|
["xpath=//a[contains(@href, '/-/user/')]", "xpath:href"],
|
||||||
|
["xpath=//div[2]/a", "xpath:position"],
|
||||||
|
["xpath=//a[contains(.,'pbadmin')]", "xpath:innerText"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "8280da13-632e-4cba-9e18-ecae0d57d052",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "linkText=Change password",
|
||||||
|
"targets": [
|
||||||
|
["linkText=Change password", "linkText"],
|
||||||
|
["css=.pf-c-nav__section:nth-child(2) .pf-c-nav__link", "css:finder"],
|
||||||
|
["xpath=//a[contains(text(),'Change password')]", "xpath:link"],
|
||||||
|
["xpath=//nav[@id='page-default-nav-example-primary-nav']/section[2]/ul/li/a", "xpath:idRelative"],
|
||||||
|
["xpath=//a[contains(@href, '/-/user/stage/password/b929b529-e384-4409-8d40-ac4a195fcab2/change/?next=%2F-%2Fuser%2F')]", "xpath:href"],
|
||||||
|
["xpath=//section[2]/ul/li/a", "xpath:position"],
|
||||||
|
["xpath=//a[contains(.,'Change password')]", "xpath:innerText"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "716d7e0c-79dc-469b-a31f-dceaa0765e9c",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "id=id_password",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password", "id"],
|
||||||
|
["name=password", "name"],
|
||||||
|
["css=#id_password", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "77005d70-adf0-4add-8329-b092d43f829a",
|
||||||
|
"comment": "",
|
||||||
|
"command": "type",
|
||||||
|
"target": "id=id_password",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password", "id"],
|
||||||
|
["name=password", "name"],
|
||||||
|
["css=#id_password", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "test"
|
||||||
|
}, {
|
||||||
|
"id": "965ca365-99f4-45d1-97c3-c944269341b9",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "id=id_password_repeat",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password_repeat", "id"],
|
||||||
|
["name=password_repeat", "name"],
|
||||||
|
["css=#id_password_repeat", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password_repeat']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div[2]/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div[2]/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}, {
|
||||||
|
"id": "9b421468-c65e-4943-b6b1-1e80410a6b87",
|
||||||
|
"comment": "",
|
||||||
|
"command": "type",
|
||||||
|
"target": "id=id_password_repeat",
|
||||||
|
"targets": [
|
||||||
|
["id=id_password_repeat", "id"],
|
||||||
|
["name=password_repeat", "name"],
|
||||||
|
["css=#id_password_repeat", "css:finder"],
|
||||||
|
["xpath=//input[@id='id_password_repeat']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div[2]/input", "xpath:idRelative"],
|
||||||
|
["xpath=//div[2]/input", "xpath:position"]
|
||||||
|
],
|
||||||
|
"value": "test"
|
||||||
|
}, {
|
||||||
|
"id": "572c1400-a0f2-499f-808a-18c1f56bf13f",
|
||||||
|
"comment": "",
|
||||||
|
"command": "click",
|
||||||
|
"target": "css=.pf-c-button",
|
||||||
|
"targets": [
|
||||||
|
["css=.pf-c-button", "css:finder"],
|
||||||
|
["xpath=//button[@type='submit']", "xpath:attributes"],
|
||||||
|
["xpath=//main[@id='flow-body']/div/form/div[3]/button", "xpath:idRelative"],
|
||||||
|
["xpath=//button", "xpath:position"],
|
||||||
|
["xpath=//button[contains(.,'Continue')]", "xpath:innerText"]
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
}]
|
||||||
}],
|
}],
|
||||||
"suites": [{
|
"suites": [{
|
||||||
"id": "495657fb-3f5e-4431-877c-4d0b248c0841",
|
"id": "495657fb-3f5e-4431-877c-4d0b248c0841",
|
||||||
|
|
|
@ -1,477 +0,0 @@
|
||||||
"""Test Enroll flow"""
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from django.test import override_settings
|
|
||||||
from selenium.webdriver.common.by import By
|
|
||||||
from selenium.webdriver.common.keys import Keys
|
|
||||||
from selenium.webdriver.support import expected_conditions as ec
|
|
||||||
|
|
||||||
from docker import DockerClient, from_env
|
|
||||||
from docker.models.containers import Container
|
|
||||||
from docker.types import Healthcheck
|
|
||||||
from e2e.utils import USER, SeleniumTestCase
|
|
||||||
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
|
|
||||||
from passbook.policies.expression.models import ExpressionPolicy
|
|
||||||
from passbook.policies.models import PolicyBinding
|
|
||||||
from passbook.stages.email.models import EmailStage, EmailTemplates
|
|
||||||
from passbook.stages.identification.models import IdentificationStage
|
|
||||||
from passbook.stages.prompt.models import FieldTypes, Prompt, PromptStage
|
|
||||||
from passbook.stages.user_login.models import UserLoginStage
|
|
||||||
from passbook.stages.user_write.models import UserWriteStage
|
|
||||||
|
|
||||||
|
|
||||||
class TestEnroll(SeleniumTestCase):
|
|
||||||
"""Test Enroll flow"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.container = self.setup_client()
|
|
||||||
|
|
||||||
def setup_client(self) -> Container:
|
|
||||||
"""Setup test IdP container"""
|
|
||||||
client: DockerClient = from_env()
|
|
||||||
container = client.containers.run(
|
|
||||||
image="mailhog/mailhog",
|
|
||||||
detach=True,
|
|
||||||
network_mode="host",
|
|
||||||
auto_remove=True,
|
|
||||||
healthcheck=Healthcheck(
|
|
||||||
test=["CMD", "wget", "-s", "http://localhost:8025"],
|
|
||||||
interval=5 * 100 * 1000000,
|
|
||||||
start_period=1 * 100 * 1000000,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
while True:
|
|
||||||
container.reload()
|
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.container.kill()
|
|
||||||
super().tearDown()
|
|
||||||
|
|
||||||
# pylint: disable=too-many-statements
|
|
||||||
def setup_test_enroll_2_step(self):
|
|
||||||
"""Setup all required objects"""
|
|
||||||
self.driver.find_element(By.ID, "id_uid_field").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
|
|
||||||
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Administrate").click()
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Prompts").click()
|
|
||||||
|
|
||||||
# Create Password Prompt
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_field_key").send_keys("password")
|
|
||||||
self.driver.find_element(By.ID, "id_label").send_keys("Password")
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_type")
|
|
||||||
dropdown.find_element(By.XPATH, "//option[. = 'Password']").click()
|
|
||||||
self.driver.find_element(By.ID, "id_placeholder").send_keys("Password")
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("1")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Password Repeat Prompt
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_field_key").send_keys("password_repeat")
|
|
||||||
self.driver.find_element(By.ID, "id_label").send_keys("Password (repeat)")
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_type")
|
|
||||||
dropdown.find_element(By.XPATH, "//option[. = 'Password']").click()
|
|
||||||
self.driver.find_element(By.ID, "id_placeholder").send_keys("Password (repeat)")
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("2")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Name Prompt
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_field_key").send_keys("name")
|
|
||||||
self.driver.find_element(By.ID, "id_label").send_keys("Name")
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_type")
|
|
||||||
dropdown.find_element(By.XPATH, "//option[. = 'Text']").click()
|
|
||||||
self.driver.find_element(By.ID, "id_placeholder").send_keys("Name")
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("0")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Email Prompt
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_field_key").send_keys("email")
|
|
||||||
self.driver.find_element(By.ID, "id_label").send_keys("Email")
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_type")
|
|
||||||
dropdown.find_element(By.XPATH, "//option[. = 'Email']").click()
|
|
||||||
self.driver.find_element(By.ID, "id_placeholder").send_keys("Email")
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("1")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Stages").click()
|
|
||||||
|
|
||||||
# Create first enroll prompt stage
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-dropdown__toggle").click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "li:nth-child(9) > .pf-c-dropdown__menu-item > small"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys(
|
|
||||||
"enroll-prompt-stage-first"
|
|
||||||
)
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_fields")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, "//option[. = \"Prompt 'username' type=text\"]"
|
|
||||||
).click()
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, "//option[. = \"Prompt 'password' type=password\"]"
|
|
||||||
).click()
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, "//option[. = \"Prompt 'password_repeat' type=password\"]"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create second enroll prompt stage
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-dropdown__toggle").click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "li:nth-child(9) > .pf-c-dropdown__menu-item"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys(
|
|
||||||
"enroll-prompt-stage-second"
|
|
||||||
)
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_fields")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, "//option[. = \"Prompt 'name' type=text\"]"
|
|
||||||
).click()
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, "//option[. = \"Prompt 'email' type=email\"]"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create user write stage
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-dropdown__toggle").click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "li:nth-child(13) > .pf-c-dropdown__menu-item"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys("enroll-user-write")
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys(Keys.ENTER)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-dropdown__toggle").click()
|
|
||||||
|
|
||||||
# Create user login stage
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "li:nth-child(11) > .pf-c-dropdown__menu-item"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys("enroll-user-login")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR,
|
|
||||||
".pf-c-nav__item:nth-child(7) .pf-c-nav__item:nth-child(1) > .pf-c-nav__link",
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create password policy
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-dropdown__toggle").click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "li:nth-child(2) > .pf-c-dropdown__menu-item > small"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys(
|
|
||||||
"policy-enrollment-password-equals"
|
|
||||||
)
|
|
||||||
self.wait.until(
|
|
||||||
ec.presence_of_element_located((By.CSS_SELECTOR, ".CodeMirror-scroll"))
|
|
||||||
)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".CodeMirror-scroll").click()
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".CodeMirror textarea").send_keys(
|
|
||||||
"return request.context['password'] == request.context['password_repeat']"
|
|
||||||
)
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create password policy binding
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR,
|
|
||||||
".pf-c-nav__item:nth-child(7) .pf-c-nav__item:nth-child(2) > .pf-c-nav__link",
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_policy")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Policy policy-enrollment-password-equals"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_target").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_target")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Prompt Stage enroll-prompt-stage-first"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("0")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Flow
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR,
|
|
||||||
".pf-c-nav__item:nth-child(6) .pf-c-nav__item:nth-child(1) > .pf-c-nav__link",
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys("Welcome")
|
|
||||||
self.driver.find_element(By.ID, "id_slug").clear()
|
|
||||||
self.driver.find_element(By.ID, "id_slug").send_keys("default-enrollment-flow")
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_designation")
|
|
||||||
dropdown.find_element(By.XPATH, '//option[. = "Enrollment"]').click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Stages").click()
|
|
||||||
|
|
||||||
# Edit identification stage
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, "tr:nth-child(11) .pf-m-secondary"
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR,
|
|
||||||
".pf-c-form__group:nth-child(5) .pf-c-form__horizontal-group",
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_enrollment_flow").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_enrollment_flow")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Flow Welcome (default-enrollment-flow)"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_user_fields_add_all_link").click()
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Bindings").click()
|
|
||||||
|
|
||||||
# Create Stage binding for first prompt stage
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_flow").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_flow")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Flow Welcome (default-enrollment-flow)"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-form").click()
|
|
||||||
self.driver.find_element(By.ID, "id_stage").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_stage")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Stage enroll-prompt-stage-first"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("0")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Stage binding for second prompt stage
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_flow").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_flow")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Flow Welcome (default-enrollment-flow)"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_stage").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_stage")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Stage enroll-prompt-stage-second"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("1")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Stage binding for user write stage
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
self.driver.find_element(By.ID, "id_flow").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_flow")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Flow Welcome (default-enrollment-flow)"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_stage").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_stage")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Stage enroll-user-write"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("2")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
# Create Stage binding for user login stage
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "Create").click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_flow")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Flow Welcome (default-enrollment-flow)"]'
|
|
||||||
).click()
|
|
||||||
dropdown = self.driver.find_element(By.ID, "id_stage")
|
|
||||||
dropdown.find_element(
|
|
||||||
By.XPATH, '//option[. = "Stage enroll-user-login"]'
|
|
||||||
).click()
|
|
||||||
self.driver.find_element(By.ID, "id_order").send_keys("3")
|
|
||||||
self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".pf-c-form__actions > .pf-m-primary"
|
|
||||||
).click()
|
|
||||||
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, "[aria-label=logout]").click()
|
|
||||||
|
|
||||||
def test_enroll_2_step(self):
|
|
||||||
"""Test 2-step enroll flow"""
|
|
||||||
self.driver.get(self.live_server_url)
|
|
||||||
self.setup_test_enroll_2_step()
|
|
||||||
self.wait.until(
|
|
||||||
ec.presence_of_element_located((By.CSS_SELECTOR, "[role=enroll]"))
|
|
||||||
)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, "[role=enroll]").click()
|
|
||||||
|
|
||||||
self.wait.until(ec.presence_of_element_located((By.ID, "id_username")))
|
|
||||||
self.driver.find_element(By.ID, "id_username").send_keys("foo")
|
|
||||||
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.ID, "id_password_repeat").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys("some name")
|
|
||||||
self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz")
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
||||||
|
|
||||||
self.wait.until(ec.presence_of_element_located((By.LINK_TEXT, "foo")))
|
|
||||||
self.driver.find_element(By.LINK_TEXT, "foo").click()
|
|
||||||
|
|
||||||
self.wait_for_url(self.url("passbook_core:user-settings"))
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text,
|
|
||||||
"foo",
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
|
|
||||||
"some name",
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
|
|
||||||
"foo@bar.baz",
|
|
||||||
)
|
|
||||||
|
|
||||||
@override_settings(EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend")
|
|
||||||
def test_enroll_email(self):
|
|
||||||
"""Test enroll with Email verification"""
|
|
||||||
# First stage fields
|
|
||||||
username_prompt = Prompt.objects.create(
|
|
||||||
field_key="username", label="Username", order=0, type=FieldTypes.TEXT
|
|
||||||
)
|
|
||||||
password = Prompt.objects.create(
|
|
||||||
field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD
|
|
||||||
)
|
|
||||||
password_repeat = Prompt.objects.create(
|
|
||||||
field_key="password_repeat",
|
|
||||||
label="Password (repeat)",
|
|
||||||
order=2,
|
|
||||||
type=FieldTypes.PASSWORD,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Second stage fields
|
|
||||||
name_field = Prompt.objects.create(
|
|
||||||
field_key="name", label="Name", order=0, type=FieldTypes.TEXT
|
|
||||||
)
|
|
||||||
email = Prompt.objects.create(
|
|
||||||
field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL
|
|
||||||
)
|
|
||||||
|
|
||||||
# Stages
|
|
||||||
first_stage = PromptStage.objects.create(name="prompt-stage-first")
|
|
||||||
first_stage.fields.set([username_prompt, password, password_repeat])
|
|
||||||
first_stage.save()
|
|
||||||
second_stage = PromptStage.objects.create(name="prompt-stage-second")
|
|
||||||
second_stage.fields.set([name_field, email])
|
|
||||||
second_stage.save()
|
|
||||||
email_stage = EmailStage.objects.create(
|
|
||||||
name="enroll-email",
|
|
||||||
host="localhost",
|
|
||||||
port=1025,
|
|
||||||
template=EmailTemplates.ACCOUNT_CONFIRM,
|
|
||||||
)
|
|
||||||
user_write = UserWriteStage.objects.create(name="enroll-user-write")
|
|
||||||
user_login = UserLoginStage.objects.create(name="enroll-user-login")
|
|
||||||
|
|
||||||
# Password checking policy
|
|
||||||
password_policy = ExpressionPolicy.objects.create(
|
|
||||||
name="policy-enrollment-password-equals",
|
|
||||||
expression="return request.context['password'] == request.context['password_repeat']",
|
|
||||||
)
|
|
||||||
PolicyBinding.objects.create(
|
|
||||||
target=first_stage, policy=password_policy, order=0
|
|
||||||
)
|
|
||||||
|
|
||||||
flow = Flow.objects.create(
|
|
||||||
name="default-enrollment-flow",
|
|
||||||
slug="default-enrollment-flow",
|
|
||||||
designation=FlowDesignation.ENROLLMENT,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Attach enrollment flow to identification stage
|
|
||||||
ident_stage: IdentificationStage = IdentificationStage.objects.first()
|
|
||||||
ident_stage.enrollment_flow = flow
|
|
||||||
ident_stage.save()
|
|
||||||
|
|
||||||
FlowStageBinding.objects.create(flow=flow, stage=first_stage, order=0)
|
|
||||||
FlowStageBinding.objects.create(flow=flow, stage=second_stage, order=1)
|
|
||||||
FlowStageBinding.objects.create(flow=flow, stage=user_write, order=2)
|
|
||||||
FlowStageBinding.objects.create(flow=flow, stage=email_stage, order=3)
|
|
||||||
FlowStageBinding.objects.create(flow=flow, stage=user_login, order=4)
|
|
||||||
|
|
||||||
self.driver.get(self.live_server_url)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, "[role=enroll]").click()
|
|
||||||
self.driver.find_element(By.ID, "id_username").send_keys("foo")
|
|
||||||
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.ID, "id_password_repeat").send_keys(USER().username)
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
||||||
self.driver.find_element(By.ID, "id_name").send_keys("some name")
|
|
||||||
self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz")
|
|
||||||
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
||||||
sleep(3)
|
|
||||||
|
|
||||||
# Open Mailhog
|
|
||||||
self.driver.get("http://localhost:8025")
|
|
||||||
|
|
||||||
# Click on first message
|
|
||||||
self.driver.find_element(By.CLASS_NAME, "msglist-message").click()
|
|
||||||
sleep(3)
|
|
||||||
self.driver.switch_to.frame(self.driver.find_element(By.CLASS_NAME, "tab-pane"))
|
|
||||||
self.driver.find_element(By.ID, "confirm").click()
|
|
||||||
self.driver.close()
|
|
||||||
self.driver.switch_to.window(self.driver.window_handles[0])
|
|
||||||
|
|
||||||
# We're now logged in
|
|
||||||
sleep(3)
|
|
||||||
self.wait.until(
|
|
||||||
ec.presence_of_element_located(
|
|
||||||
(By.XPATH, "//a[contains(@href, '/-/user/')]")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text,
|
|
||||||
"foo",
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
|
|
||||||
"some name",
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
|
|
||||||
"foo@bar.baz",
|
|
||||||
)
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
"""Test Enroll flow"""
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from django.test import override_settings
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support import expected_conditions as ec
|
||||||
|
|
||||||
|
from docker import DockerClient, from_env
|
||||||
|
from docker.models.containers import Container
|
||||||
|
from docker.types import Healthcheck
|
||||||
|
from e2e.utils import USER, SeleniumTestCase
|
||||||
|
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
|
||||||
|
from passbook.policies.expression.models import ExpressionPolicy
|
||||||
|
from passbook.policies.models import PolicyBinding
|
||||||
|
from passbook.stages.email.models import EmailStage, EmailTemplates
|
||||||
|
from passbook.stages.identification.models import IdentificationStage
|
||||||
|
from passbook.stages.prompt.models import FieldTypes, Prompt, PromptStage
|
||||||
|
from passbook.stages.user_login.models import UserLoginStage
|
||||||
|
from passbook.stages.user_write.models import UserWriteStage
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlowsEnroll(SeleniumTestCase):
|
||||||
|
"""Test Enroll flow"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.container = self.setup_client()
|
||||||
|
|
||||||
|
def setup_client(self) -> Container:
|
||||||
|
"""Setup test IdP container"""
|
||||||
|
client: DockerClient = from_env()
|
||||||
|
container = client.containers.run(
|
||||||
|
image="mailhog/mailhog",
|
||||||
|
detach=True,
|
||||||
|
network_mode="host",
|
||||||
|
auto_remove=True,
|
||||||
|
healthcheck=Healthcheck(
|
||||||
|
test=["CMD", "wget", "-s", "http://localhost:8025"],
|
||||||
|
interval=5 * 100 * 1000000,
|
||||||
|
start_period=1 * 100 * 1000000,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
container.reload()
|
||||||
|
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
||||||
|
if status == "healthy":
|
||||||
|
return container
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.container.kill()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
def test_enroll_2_step(self):
|
||||||
|
"""Test 2-step enroll flow"""
|
||||||
|
# First stage fields
|
||||||
|
username_prompt = Prompt.objects.create(
|
||||||
|
field_key="username", label="Username", order=0, type=FieldTypes.TEXT
|
||||||
|
)
|
||||||
|
password = Prompt.objects.create(
|
||||||
|
field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD
|
||||||
|
)
|
||||||
|
password_repeat = Prompt.objects.create(
|
||||||
|
field_key="password_repeat",
|
||||||
|
label="Password (repeat)",
|
||||||
|
order=2,
|
||||||
|
type=FieldTypes.PASSWORD,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Second stage fields
|
||||||
|
name_field = Prompt.objects.create(
|
||||||
|
field_key="name", label="Name", order=0, type=FieldTypes.TEXT
|
||||||
|
)
|
||||||
|
email = Prompt.objects.create(
|
||||||
|
field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stages
|
||||||
|
first_stage = PromptStage.objects.create(name="prompt-stage-first")
|
||||||
|
first_stage.fields.set([username_prompt, password, password_repeat])
|
||||||
|
first_stage.save()
|
||||||
|
second_stage = PromptStage.objects.create(name="prompt-stage-second")
|
||||||
|
second_stage.fields.set([name_field, email])
|
||||||
|
second_stage.save()
|
||||||
|
user_write = UserWriteStage.objects.create(name="enroll-user-write")
|
||||||
|
user_login = UserLoginStage.objects.create(name="enroll-user-login")
|
||||||
|
|
||||||
|
# Password checking policy
|
||||||
|
password_policy = ExpressionPolicy.objects.create(
|
||||||
|
name="policy-enrollment-password-equals",
|
||||||
|
expression="return request.context['password'] == request.context['password_repeat']",
|
||||||
|
)
|
||||||
|
PolicyBinding.objects.create(
|
||||||
|
target=first_stage, policy=password_policy, order=0
|
||||||
|
)
|
||||||
|
|
||||||
|
flow = Flow.objects.create(
|
||||||
|
name="default-enrollment-flow",
|
||||||
|
slug="default-enrollment-flow",
|
||||||
|
designation=FlowDesignation.ENROLLMENT,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Attach enrollment flow to identification stage
|
||||||
|
ident_stage: IdentificationStage = IdentificationStage.objects.first()
|
||||||
|
ident_stage.enrollment_flow = flow
|
||||||
|
ident_stage.save()
|
||||||
|
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=first_stage, order=0)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=second_stage, order=1)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=user_write, order=2)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=user_login, order=3)
|
||||||
|
|
||||||
|
self.driver.get(self.live_server_url)
|
||||||
|
self.wait.until(
|
||||||
|
ec.presence_of_element_located((By.CSS_SELECTOR, "[role=enroll]"))
|
||||||
|
)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, "[role=enroll]").click()
|
||||||
|
|
||||||
|
self.wait.until(ec.presence_of_element_located((By.ID, "id_username")))
|
||||||
|
self.driver.find_element(By.ID, "id_username").send_keys("foo")
|
||||||
|
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.ID, "id_password_repeat").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
||||||
|
self.driver.find_element(By.ID, "id_name").send_keys("some name")
|
||||||
|
self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz")
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
||||||
|
|
||||||
|
self.wait.until(ec.presence_of_element_located((By.LINK_TEXT, "foo")))
|
||||||
|
self.driver.find_element(By.LINK_TEXT, "foo").click()
|
||||||
|
|
||||||
|
self.wait_for_url(self.url("passbook_core:user-settings"))
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text,
|
||||||
|
"foo",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
|
||||||
|
"some name",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
|
||||||
|
"foo@bar.baz",
|
||||||
|
)
|
||||||
|
|
||||||
|
@override_settings(EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend")
|
||||||
|
def test_enroll_email(self):
|
||||||
|
"""Test enroll with Email verification"""
|
||||||
|
# First stage fields
|
||||||
|
username_prompt = Prompt.objects.create(
|
||||||
|
field_key="username", label="Username", order=0, type=FieldTypes.TEXT
|
||||||
|
)
|
||||||
|
password = Prompt.objects.create(
|
||||||
|
field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD
|
||||||
|
)
|
||||||
|
password_repeat = Prompt.objects.create(
|
||||||
|
field_key="password_repeat",
|
||||||
|
label="Password (repeat)",
|
||||||
|
order=2,
|
||||||
|
type=FieldTypes.PASSWORD,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Second stage fields
|
||||||
|
name_field = Prompt.objects.create(
|
||||||
|
field_key="name", label="Name", order=0, type=FieldTypes.TEXT
|
||||||
|
)
|
||||||
|
email = Prompt.objects.create(
|
||||||
|
field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stages
|
||||||
|
first_stage = PromptStage.objects.create(name="prompt-stage-first")
|
||||||
|
first_stage.fields.set([username_prompt, password, password_repeat])
|
||||||
|
first_stage.save()
|
||||||
|
second_stage = PromptStage.objects.create(name="prompt-stage-second")
|
||||||
|
second_stage.fields.set([name_field, email])
|
||||||
|
second_stage.save()
|
||||||
|
email_stage = EmailStage.objects.create(
|
||||||
|
name="enroll-email",
|
||||||
|
host="localhost",
|
||||||
|
port=1025,
|
||||||
|
template=EmailTemplates.ACCOUNT_CONFIRM,
|
||||||
|
)
|
||||||
|
user_write = UserWriteStage.objects.create(name="enroll-user-write")
|
||||||
|
user_login = UserLoginStage.objects.create(name="enroll-user-login")
|
||||||
|
|
||||||
|
# Password checking policy
|
||||||
|
password_policy = ExpressionPolicy.objects.create(
|
||||||
|
name="policy-enrollment-password-equals",
|
||||||
|
expression="return request.context['password'] == request.context['password_repeat']",
|
||||||
|
)
|
||||||
|
PolicyBinding.objects.create(
|
||||||
|
target=first_stage, policy=password_policy, order=0
|
||||||
|
)
|
||||||
|
|
||||||
|
flow = Flow.objects.create(
|
||||||
|
name="default-enrollment-flow",
|
||||||
|
slug="default-enrollment-flow",
|
||||||
|
designation=FlowDesignation.ENROLLMENT,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Attach enrollment flow to identification stage
|
||||||
|
ident_stage: IdentificationStage = IdentificationStage.objects.first()
|
||||||
|
ident_stage.enrollment_flow = flow
|
||||||
|
ident_stage.save()
|
||||||
|
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=first_stage, order=0)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=second_stage, order=1)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=user_write, order=2)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=email_stage, order=3)
|
||||||
|
FlowStageBinding.objects.create(flow=flow, stage=user_login, order=4)
|
||||||
|
|
||||||
|
self.driver.get(self.live_server_url)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, "[role=enroll]").click()
|
||||||
|
self.driver.find_element(By.ID, "id_username").send_keys("foo")
|
||||||
|
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.ID, "id_password_repeat").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
||||||
|
self.driver.find_element(By.ID, "id_name").send_keys("some name")
|
||||||
|
self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz")
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
||||||
|
sleep(3)
|
||||||
|
|
||||||
|
# Open Mailhog
|
||||||
|
self.driver.get("http://localhost:8025")
|
||||||
|
|
||||||
|
# Click on first message
|
||||||
|
self.driver.find_element(By.CLASS_NAME, "msglist-message").click()
|
||||||
|
sleep(3)
|
||||||
|
self.driver.switch_to.frame(self.driver.find_element(By.CLASS_NAME, "tab-pane"))
|
||||||
|
self.driver.find_element(By.ID, "confirm").click()
|
||||||
|
self.driver.close()
|
||||||
|
self.driver.switch_to.window(self.driver.window_handles[0])
|
||||||
|
|
||||||
|
# We're now logged in
|
||||||
|
sleep(3)
|
||||||
|
self.wait.until(
|
||||||
|
ec.presence_of_element_located(
|
||||||
|
(By.XPATH, "//a[contains(@href, '/-/user/')]")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text,
|
||||||
|
"foo",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
|
||||||
|
"some name",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
|
||||||
|
"foo@bar.baz",
|
||||||
|
)
|
|
@ -5,7 +5,7 @@ from selenium.webdriver.common.keys import Keys
|
||||||
from e2e.utils import USER, SeleniumTestCase
|
from e2e.utils import USER, SeleniumTestCase
|
||||||
|
|
||||||
|
|
||||||
class TestLogin(SeleniumTestCase):
|
class TestFlowsLogin(SeleniumTestCase):
|
||||||
"""test default login flow"""
|
"""test default login flow"""
|
||||||
|
|
||||||
def test_login(self):
|
def test_login(self):
|
|
@ -0,0 +1,41 @@
|
||||||
|
"""test stage setup flows (password change)"""
|
||||||
|
import string
|
||||||
|
from random import SystemRandom
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
|
||||||
|
from e2e.utils import USER, SeleniumTestCase
|
||||||
|
from passbook.core.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlowsStageSetup(SeleniumTestCase):
|
||||||
|
"""test stage setup flows"""
|
||||||
|
|
||||||
|
def test_password_change(self):
|
||||||
|
"""test password change flow"""
|
||||||
|
new_password = "".join(
|
||||||
|
SystemRandom().choice(string.ascii_uppercase + string.digits)
|
||||||
|
for _ in range(8)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.driver.get(
|
||||||
|
f"{self.live_server_url}/flows/default-authentication-flow/?next=%2F"
|
||||||
|
)
|
||||||
|
self.driver.find_element(By.ID, "id_uid_field").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
|
||||||
|
self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
|
||||||
|
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()
|
||||||
|
self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click()
|
||||||
|
self.driver.find_element(By.LINK_TEXT, "Change password").click()
|
||||||
|
self.driver.find_element(By.ID, "id_password").send_keys(new_password)
|
||||||
|
self.driver.find_element(By.ID, "id_password_repeat").click()
|
||||||
|
self.driver.find_element(By.ID, "id_password_repeat").send_keys(new_password)
|
||||||
|
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
||||||
|
|
||||||
|
sleep(2)
|
||||||
|
# Because USER() is cached, we need to get the user manually here
|
||||||
|
user = User.objects.get(username=USER().username)
|
||||||
|
self.assertTrue(user.check_password(new_password))
|
|
@ -82,6 +82,22 @@ def create_default_password_change(apps: Apps, schema_editor: BaseDatabaseSchema
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def update_default_stage_change(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||||
|
PasswordStage = apps.get_model("passbook_stages_password", "PasswordStage")
|
||||||
|
Flow = apps.get_model("passbook_flows", "Flow")
|
||||||
|
|
||||||
|
flow = Flow.objects.get(
|
||||||
|
slug="default-password-change", designation=FlowDesignation.STAGE_SETUP,
|
||||||
|
)
|
||||||
|
|
||||||
|
stages = PasswordStage.objects.filter(name="default-authentication-password")
|
||||||
|
if not stages.exists():
|
||||||
|
return
|
||||||
|
stage = stages.first()
|
||||||
|
stage.change_flow = flow
|
||||||
|
stage.save()
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
@ -106,4 +122,5 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.RunPython(create_default_password_change),
|
migrations.RunPython(create_default_password_change),
|
||||||
|
migrations.RunPython(update_default_stage_change),
|
||||||
]
|
]
|
||||||
|
|
|
@ -44,7 +44,7 @@ class PasswordStage(Stage):
|
||||||
"passbook_stages_password:change", kwargs={"stage_uuid": self.pk}
|
"passbook_stages_password:change", kwargs={"stage_uuid": self.pk}
|
||||||
)
|
)
|
||||||
args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")})
|
args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")})
|
||||||
return UIUserSettings(name=self.name, url=f"{base_url}?{args}")
|
return UIUserSettings(name=_("Change password"), url=f"{base_url}?{args}")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Password Stage {self.name}"
|
return f"Password Stage {self.name}"
|
||||||
|
|
Reference in New Issue