mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
* web: Add InvalidationFlow to Radius Provider dialogues
## What
- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
- Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`
## Note
Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.
* This (temporary) change is needed to prevent the unit tests from failing.
\# What
\# Why
\# How
\# Designs
\# Test Steps
\# Other Notes
* Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit dddde09be5.
* website: fix bad escaping of URLs in release notes
## What
Fixes bad escaping of URLs in the release notes that resulted in mangled output.
v2024.6.4 had entries that looked like this:
```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```
v2025.4.md had entries that looked like this:
```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```
A couple of straightforward search-and-replaces has fixed the issue.
## Notes
Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.
@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.
The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
* web/maintenance/no-unknown-attributes-1
# What
This commit is a collection of fixes and adaptations discovered while running lit-analyzer in a stricter role than usual. These fixes are to 9 of the existing issues; there are 16 more that will be addressed in the next two pull requests.
The following issues were uncovered.
- `ak-slug-input` does not take `autocomplete`.
- `ak-wizard-page-type-create` does not take, or use, the `name` attribute. It also has no `value` of its own, so it is not processed as a form object.
- `ak-endpoints-device-access-groups-form` does not take a `pk` attribute. It takes an `.instancePk` property.
- `ak-provider-oauth2-redirect-uri` is only used in one place, and that place uses the term `input-id` for the key. The component was expected `inputId`. Since it is a string and therefore an attribute, kebab-case is the appropriate fix here.
- `input-mode` is not a valid attribute. The attribute is `inputmode`, and the property is `inputMode`. It may not be undefined. If it is defined, the default is `text`. I have fixed this in the attribute and in the two Forms that used it.
- `form-associated-element` had both `name` and `type` as readonly. Since they are native attributes, they can be attributes or they can be readonly. They can’t be both. I have made them read-write.
- `user-source-settings-page` is only used in one place, and that place uses the term `input-id` for the key. The component was expected `inputId`. Since it is a string and therefore an attribute, kebab-case is the appropriate fix here.
These guideposts will be placed on the PR.
* Update web/src/admin/providers/oauth2/OAuth2ProviderRedirectURI.ts
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
* Update web/src/components/ak-text-input.ts
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
* web/maintenance/no-unknown-attributes-2
# What
This commit is a collection of fixes and adaptations discovered while running lit-analyzer in a stricter role than usual.
- `src/admin/endpoints/connectors/agent/AgentConnectorSetup.ts`
After talking to @beryju, we determined that these labels aren’t shown and aren’t used.
- `src/admin/admin-overview/AdminOverviewPage.ts`
- `src/admin/admin-overview/DashboardUserPage.ts`
- `src/elements/cards/AggregatePromiseCard.ts`
- `src/elements/cards/stories/AggregatePromiseCard.stories.ts`
The `Promise` version of our card is not used by any client code. The Dashboard pages that were importing it want the vanilla `AggregateCard` instead.
- `./src/flow/stages/identification/IdentificationStage.ts`
Anchors do not have a `name` attribute, I cannot find any code using the name attributes as lookups, nor any CSS that might use the name attributes as guides. `ak-flow-password-input` is always required; the flag is unsupported and unnecessary.
- `./src/flow/stages/password/PasswordStage.ts`
Anchors do not have a `name` attribute, I cannot find any code using the name attributes as lookups, nor any CSS that might use the name attributes as guides. `ak-flow-password-input` is always required; the flag is unsupported and unnecessary.
- `src/user/user-settings/UserSettingsPage.ts`
This change to the `UserSettingsPage`:
``` diff
- userId=${ifPresent(currentUser?.pk)}
+ user-id=${ifPresent(currentUser?.pk)}
```
… corresponds correctly with:
``` typescript
@property({ type: Number, attribute: "user-id" })
public userId?: number;
```
I find it odd (and remarkable) that nobody has complained about this yet. I even went so far as to [confirm my understanding](https://codepen.io/kensternberg-authentik/pen/raLNBwO) and, yes:
- when an attribute is truthy, property syntax does not set the field
- when an attribute is deliberately given a kebab-case name, using the camelCase variant does not set the field
However, when the attribute is truthy, attribute names are case-insensitive: ‘user-id’ and ‘User-Id’ in client code would work just fine.
## Note
A large enough number of warnings remain. Some of those are due to `lit-analyzer` not being updated to recognize newly Baseline global DOM properties like `inert` or `popover`. The rest are from RapiDoc and QrCode, which do not supply sufficient documentation or metadata for Lit-anaylzer to read correctly.
* web/bug/hidden-secrets-not-propagating
# What
This commit updates ak-secret-text-input, adding the `name` attribute to all valid input fields and updating the value writer to match those of known-working components, to ensure that either variety of the display is fully and correctly updated with the content of the hidden secret.
# Why
The hidden input field is the one that HorizontalFormElement was expecting to read its value from, but that field never received a `name` because it wasn’t present when the field was first updated.
HorizontalFormElement writes the `name` field to the first `<input>` it finds. That was the “dummy” input field, which has no working value.
Form ignored the input element because the value it read came with an undefined name.
Object-oriented state management sometimes bites.
* Turns out, I was wrong. Someone *does* use the `name` attribute: the tests. MDN says that `name`
is incorrect, and we should use `id` instead. I have compromised; I have switched to using the
Open UI Automation ID instead, since that's what we're doing: automated tests.
\# What
\# Why
\# How
\# Designs
\# Test Steps
\# Other Notes
---------
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Jens L. <jens@goauthentik.io>
114 lines
4.5 KiB
Python
114 lines
4.5 KiB
Python
"""Test recovery flow"""
|
|
|
|
from time import sleep
|
|
|
|
from selenium.webdriver.common.by import By
|
|
from selenium.webdriver.support import expected_conditions as ec
|
|
from selenium.webdriver.support.wait import WebDriverWait
|
|
|
|
from authentik.blueprints.tests import apply_blueprint
|
|
from authentik.core.models import User
|
|
from authentik.core.tests.utils import create_test_admin_user
|
|
from authentik.flows.models import Flow
|
|
from authentik.lib.config import CONFIG
|
|
from authentik.lib.generators import generate_id
|
|
from authentik.stages.identification.models import IdentificationStage
|
|
from tests.e2e.utils import SeleniumTestCase, retry
|
|
|
|
|
|
class TestFlowsRecovery(SeleniumTestCase):
|
|
"""Test Recovery flow"""
|
|
|
|
def initial_stages(self, user: User):
|
|
"""Fill out initial stages"""
|
|
# Identification stage, click recovery
|
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
|
wait = WebDriverWait(identification_stage, self.wait_timeout)
|
|
|
|
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "a[ouiaId='recovery']")))
|
|
identification_stage.find_element(By.CSS_SELECTOR, "a[ouiaId='recovery']").click()
|
|
|
|
# First prompt stage
|
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
|
wait = WebDriverWait(identification_stage, self.wait_timeout)
|
|
|
|
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=uidField]")))
|
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uidField]").send_keys(
|
|
user.username
|
|
)
|
|
identification_stage.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
|
|
@retry()
|
|
@apply_blueprint(
|
|
"default/flow-default-authentication-flow.yaml",
|
|
"default/flow-default-invalidation-flow.yaml",
|
|
)
|
|
@apply_blueprint(
|
|
"example/flows-recovery-email-verification.yaml",
|
|
)
|
|
@CONFIG.patch("email.port", 1025)
|
|
def test_recover_email(self):
|
|
"""Test recovery with Email verification"""
|
|
# Attach recovery flow to identification stage
|
|
ident_stage: IdentificationStage = IdentificationStage.objects.get(
|
|
name="default-authentication-identification"
|
|
)
|
|
ident_stage.recovery_flow = Flow.objects.filter(slug="default-recovery-flow").first()
|
|
ident_stage.save()
|
|
|
|
user = create_test_admin_user()
|
|
|
|
self.driver.get(self.live_server_url)
|
|
self.initial_stages(user)
|
|
|
|
# Email stage
|
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
email_stage = self.get_shadow_root("ak-stage-email", flow_executor)
|
|
|
|
wait = WebDriverWait(email_stage, self.wait_timeout)
|
|
|
|
# Wait for the success message so we know the email is sent
|
|
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, ".pf-c-form p")))
|
|
|
|
# Open mailpit
|
|
self.driver.get("http://localhost:8025")
|
|
|
|
# Click on first message
|
|
self.wait.until(ec.presence_of_element_located((By.CLASS_NAME, "message")))
|
|
self.driver.find_element(By.CLASS_NAME, "message").click()
|
|
self.driver.switch_to.frame(self.driver.find_element(By.ID, "preview-html"))
|
|
self.driver.find_element(By.ID, "confirm").click()
|
|
self.driver.close()
|
|
self.driver.switch_to.window(self.driver.window_handles[0])
|
|
|
|
sleep(2)
|
|
|
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
|
|
consent_stage.find_element(
|
|
By.CSS_SELECTOR,
|
|
"[type=submit]",
|
|
).click()
|
|
|
|
# We can now enter the new password
|
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
|
prompt_stage = self.get_shadow_root("ak-stage-prompt", flow_executor)
|
|
wait = WebDriverWait(prompt_stage, self.wait_timeout)
|
|
|
|
new_password = generate_id()
|
|
|
|
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "input[name=password]")))
|
|
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(new_password)
|
|
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=password_repeat]").send_keys(
|
|
new_password
|
|
)
|
|
prompt_stage.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
|
|
sleep(2)
|
|
|
|
# We're now logged in
|
|
self.assert_user(user)
|
|
user.refresh_from_db()
|
|
self.assertTrue(user.check_password(new_password))
|