diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index e78a3568dc..ede5438bd6 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -64,7 +64,7 @@ runs: rustflags: "" - name: Setup rust dependencies if: ${{ contains(inputs.dependencies, 'rust') }} - uses: taiki-e/install-action@7be9fd86bd1707236395105d6e9329dd1511a7e1 # v2 + uses: taiki-e/install-action@b550161ef8a7bc4f2a671c0b03a18ac9ccedea1e # v2 with: tool: cargo-deny cargo-machete cargo-llvm-cov nextest - name: Setup node (root, web) diff --git a/.github/actions/test-results/action.yml b/.github/actions/test-results/action.yml index c5fb631ad6..017453bbee 100644 --- a/.github/actions/test-results/action.yml +++ b/.github/actions/test-results/action.yml @@ -10,12 +10,12 @@ inputs: runs: using: "composite" steps: - - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5 + - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v5 with: files: ${{ inputs.files }} flags: ${{ inputs.flags }} use_oidc: true - - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5 + - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v5 with: files: ${{ inputs.files }} flags: ${{ inputs.flags }} diff --git a/lifecycle/container/Dockerfile b/lifecycle/container/Dockerfile index e59dbb008f..a24b43f2b5 100644 --- a/lifecycle/container/Dockerfile +++ b/lifecycle/container/Dockerfile @@ -115,9 +115,9 @@ RUN --mount=type=bind,target=rust-toolchain.toml,src=rust-toolchain.toml \ RUN cat /root/.rustup/settings.toml # Stage: Download uv -FROM ghcr.io/astral-sh/uv:0.11.5@sha256:555ac94f9a22e656fc5f2ce5dfee13b04e94d099e46bb8dd3a73ec7263f2e484 AS uv +FROM ghcr.io/astral-sh/uv:0.11.15@sha256:e590846f4776907b254ac0f44b5b380347af5d90d668138ca7938d1b0c2f98d3 AS uv # Stage: Base python image -FROM ghcr.io/goauthentik/fips-python:3.14.3-slim-trixie-fips@sha256:bf45eb77a010d76fe6abd7ae137d1b0c44b6227cd984945042135fdf05ebf8d9 AS python-base +FROM ghcr.io/goauthentik/fips-python:3.14.5-slim-trixie-fips@sha256:4fde79ded5d9c341576aa423b6637fcce465f89b48fabbebebdc8273a5cb0a1f AS python-base ENV VENV_PATH="/ak-root/.venv" \ PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \ diff --git a/pyproject.toml b/pyproject.toml index 286d36ad2d..ecc489f524 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,7 @@ dependencies = [ [dependency-groups] dev = [ - "aws-cdk-lib==2.253.1", + "aws-cdk-lib==2.254.0", "bandit==1.9.4", "black==26.3.1", "bpython==0.26", diff --git a/uv.lock b/uv.lock index ca373c5df5..6a2de707f7 100644 --- a/uv.lock +++ b/uv.lock @@ -385,7 +385,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "aws-cdk-lib", specifier = "==2.253.1" }, + { name = "aws-cdk-lib", specifier = "==2.254.0" }, { name = "bandit", specifier = "==1.9.4" }, { name = "black", specifier = "==26.3.1" }, { name = "bpython", specifier = "==0.26" }, @@ -481,21 +481,21 @@ wheels = [ [[package]] name = "aws-cdk-cloud-assembly-schema" -version = "53.20.0" +version = "53.27.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsii" }, { name = "publication" }, { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/8a/3b94fbba0d8ca4123eb015ea12a1c8fc5193a1eddcc4d69d31b9575546c8/aws_cdk_cloud_assembly_schema-53.20.0.tar.gz", hash = "sha256:c5d884f7211fd18cc0ce8c4349902ab6a6b3cd8f3c2259c56616a59218c221eb", size = 212292, upload-time = "2026-04-30T11:34:29.29Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/0d/791712ae1337471c98ad9ebca33390e242fbb20508ffeb03f17664c755e2/aws_cdk_cloud_assembly_schema-53.27.0.tar.gz", hash = "sha256:d1588da5c4b0d5de2d611923e6120b302f5280cf328e5984da8ecff9ae87a751", size = 223242, upload-time = "2026-05-20T15:55:02.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/eb/7bf100ad3603d5fbbebb49b3d48add58abda59c3fa44a4a7eae40da5b8d0/aws_cdk_cloud_assembly_schema-53.20.0-py3-none-any.whl", hash = "sha256:b68ea0754ec830751d4a375ebe84d4c077dc488a2498c3607a2f998bc7e91d73", size = 212140, upload-time = "2026-04-30T11:34:27.044Z" }, + { url = "https://files.pythonhosted.org/packages/af/a6/c4ce05dc7e4b8e941ae910362b87747879423e7eb6196c913632894f1af0/aws_cdk_cloud_assembly_schema-53.27.0-py3-none-any.whl", hash = "sha256:04c4091905d3365a8d9109eda5762e59dbdc897995150cc7e703057168f833c1", size = 222824, upload-time = "2026-05-20T15:55:00.266Z" }, ] [[package]] name = "aws-cdk-lib" -version = "2.253.1" +version = "2.254.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aws-cdk-asset-awscli-v1" }, @@ -506,9 +506,9 @@ dependencies = [ { name = "publication" }, { name = "typeguard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/58/f4104842e277f000396f9f9e12588eb83615a1212fb3ee1668bb5dd1f97a/aws_cdk_lib-2.253.1.tar.gz", hash = "sha256:df03363cdaef4d2d7bac368b2d5d2bf4209921d21096cd5f8e5889347fee4793", size = 49586746, upload-time = "2026-05-08T16:05:27.185Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/94/667be78bf5f39aef15ff34778eda0443bb4ad2498f33ccb6f7629f343f43/aws_cdk_lib-2.254.0.tar.gz", hash = "sha256:ddbef134cad91f8985444f77f052f0337af5f132101ad7aea2215b4775ff7828", size = 49658861, upload-time = "2026-05-13T21:59:39.35Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/7c/1e7964f0f267301bb5026fed45369961f7311073412bcd36e09fbe4df0de/aws_cdk_lib-2.253.1-py3-none-any.whl", hash = "sha256:03a6f5080978f9e3576f490d06fbd1f41f159280d34dbca50721de4a19694136", size = 50271288, upload-time = "2026-05-08T16:04:41.956Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/13c490cba548fde101663fb6d9050eeee67686a9730e74cba5711ba12068/aws_cdk_lib-2.254.0-py3-none-any.whl", hash = "sha256:626095eaa742e0b9d894c3a1bf06a6e7d1245a986165a72408871d41886c6d07", size = 50343718, upload-time = "2026-05-13T21:58:54.123Z" }, ] [[package]] @@ -1923,7 +1923,7 @@ wheels = [ [[package]] name = "jsii" -version = "1.128.0" +version = "1.131.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1934,9 +1934,9 @@ dependencies = [ { name = "typeguard" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/10/21/e11ec4d974665d5d5d36e19a8546d9d58b1943794b214dd5eeea09d04aa7/jsii-1.128.0.tar.gz", hash = "sha256:05f21e1c16e899cd65db27e54c9379b561cf368c6d670b60ea012bffa801b6d7", size = 444659, upload-time = "2026-04-09T17:31:46.796Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/24/8afffbbe472a0b044b08cca8a6a64fbe3f2e1b7943f522675f8f037275cf/jsii-1.131.0.tar.gz", hash = "sha256:ba3ec253056ede00635a9aed7a68f7224b456cf6dd85538c499c884f69b517f7", size = 445209, upload-time = "2026-05-19T10:08:24.235Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/17/963cc6f0cb8b143649c0371a4b293490811c2ff2d3707511202e192dd272/jsii-1.128.0-py3-none-any.whl", hash = "sha256:25912f66516c08c21dfcd350c9efd4c71548a98fd1af61ed08e73d99a73e0af0", size = 417867, upload-time = "2026-04-09T17:31:45.441Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2a/630b34e306342477d538b16efb073749bcd9b08174442bf37f361ac7c8a2/jsii-1.131.0-py3-none-any.whl", hash = "sha256:99426379fe8a0e8bcca9bd1ce04440d5dd6bb987ebb95ecf53e5a52271362d17", size = 418408, upload-time = "2026-05-19T10:08:22.565Z" }, ] [[package]] diff --git a/web/src/admin/ak-interface-admin.ts b/web/src/admin/ak-interface-admin.ts index e185684b49..71b8d67887 100644 --- a/web/src/admin/ak-interface-admin.ts +++ b/web/src/admin/ak-interface-admin.ts @@ -29,15 +29,16 @@ import { renderDialog } from "#elements/dialogs"; import { WithCapabilitiesConfig } from "#elements/mixins/capabilities"; import { WithNotifications } from "#elements/mixins/notifications"; import { canAccessAdmin, WithSession } from "#elements/mixins/session"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; +import { navigate } from "#elements/router/RouterOutlet"; +import { SlottedTemplateResult } from "#elements/types"; + +import { AKDrawerChangeEvent } from "#components/notifications/events"; import { DrawerState, persistDrawerParams, readDrawerParams, renderNotificationDrawerPanel, -} from "#elements/notifications/utils"; -import { navigate } from "#elements/router/RouterOutlet"; -import { SlottedTemplateResult } from "#elements/types"; +} from "#components/notifications/utils"; import Styles from "#admin/ak-interface-admin.css"; import { ROUTES } from "#admin/Routes"; diff --git a/web/src/admin/outposts/OutpostProviderList.ts b/web/src/admin/outposts/OutpostProviderList.ts index 583be38b43..5bb1b3344a 100644 --- a/web/src/admin/outposts/OutpostProviderList.ts +++ b/web/src/admin/outposts/OutpostProviderList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import "#admin/common/ak-flow-search/ak-flow-search-no-default"; import { StaticTable } from "#elements/table/StaticTable"; diff --git a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderGroupList.ts b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderGroupList.ts index ca8b02f876..d00bad437c 100644 --- a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderGroupList.ts +++ b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderGroupList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import { DEFAULT_CONFIG } from "#common/api/config"; diff --git a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderUserList.ts b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderUserList.ts index 14f7bb7604..2ecd02ec6b 100644 --- a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderUserList.ts +++ b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderUserList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import { DEFAULT_CONFIG } from "#common/api/config"; import { formatUserDisplayName } from "#common/users"; diff --git a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage.ts b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage.ts index f48b1670f2..c2842ac80f 100644 --- a/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage.ts +++ b/web/src/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage.ts @@ -8,7 +8,7 @@ import "#admin/events/ObjectChangelog"; import "#elements/Tabs"; import "#elements/buttons/ActionButton/index"; import "#elements/buttons/ModalButton"; -import "#elements/sync/SyncStatusCard"; +import "#components/sync/SyncStatusCard"; import "#elements/tasks/ScheduleList"; import "#elements/tasks/TaskList"; diff --git a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderGroupList.ts b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderGroupList.ts index 73487bf5f6..8835160b2f 100644 --- a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderGroupList.ts +++ b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderGroupList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import { DEFAULT_CONFIG } from "#common/api/config"; diff --git a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderUserList.ts b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderUserList.ts index 872281aded..5bf3416ee2 100644 --- a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderUserList.ts +++ b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderUserList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import { DEFAULT_CONFIG } from "#common/api/config"; import { formatUserDisplayName } from "#common/users"; diff --git a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage.ts b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage.ts index a6f2646e5e..89df2e453f 100644 --- a/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage.ts +++ b/web/src/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage.ts @@ -8,7 +8,7 @@ import "#elements/Tabs"; import "#elements/buttons/ActionButton/index"; import "#elements/buttons/ModalButton"; import "#elements/events/LogViewer"; -import "#elements/sync/SyncStatusCard"; +import "#components/sync/SyncStatusCard"; import "#elements/tasks/ScheduleList"; import "#elements/tasks/TaskList"; diff --git a/web/src/admin/providers/scim/SCIMProviderGroupList.ts b/web/src/admin/providers/scim/SCIMProviderGroupList.ts index 6eda4408ae..90b3f9eb45 100644 --- a/web/src/admin/providers/scim/SCIMProviderGroupList.ts +++ b/web/src/admin/providers/scim/SCIMProviderGroupList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import "#admin/common/ak-flow-search/ak-flow-search-no-default"; import { DEFAULT_CONFIG } from "#common/api/config"; diff --git a/web/src/admin/providers/scim/SCIMProviderUserList.ts b/web/src/admin/providers/scim/SCIMProviderUserList.ts index d91dd086c2..d137c1ac9c 100644 --- a/web/src/admin/providers/scim/SCIMProviderUserList.ts +++ b/web/src/admin/providers/scim/SCIMProviderUserList.ts @@ -1,6 +1,6 @@ import "#elements/forms/DeleteBulkForm"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncObjectForm"; +import "#components/sync/SyncObjectForm"; import "#admin/common/ak-flow-search/ak-flow-search-no-default"; import { DEFAULT_CONFIG } from "#common/api/config"; diff --git a/web/src/admin/providers/scim/SCIMProviderViewPage.ts b/web/src/admin/providers/scim/SCIMProviderViewPage.ts index c54bfa36f5..ab80988bc6 100644 --- a/web/src/admin/providers/scim/SCIMProviderViewPage.ts +++ b/web/src/admin/providers/scim/SCIMProviderViewPage.ts @@ -10,7 +10,7 @@ import "#elements/Tabs"; import "#elements/ak-mdx/index"; import "#elements/buttons/ActionButton/index"; import "#elements/buttons/ModalButton"; -import "#elements/sync/SyncStatusCard"; +import "#components/sync/SyncStatusCard"; import "#elements/tasks/ScheduleList"; import "#elements/tasks/TaskList"; import "#elements/timestamp/ak-timestamp"; diff --git a/web/src/admin/sources/kerberos/KerberosSourceViewPage.ts b/web/src/admin/sources/kerberos/KerberosSourceViewPage.ts index 5ea685f1fc..02e23e78bf 100644 --- a/web/src/admin/sources/kerberos/KerberosSourceViewPage.ts +++ b/web/src/admin/sources/kerberos/KerberosSourceViewPage.ts @@ -9,7 +9,7 @@ import "#elements/ak-mdx/index"; import "#elements/buttons/ActionButton/index"; import "#elements/buttons/SpinnerButton/index"; import "#elements/forms/ModalForm"; -import "#elements/sync/SyncStatusCard"; +import "#components/sync/SyncStatusCard"; import { DEFAULT_CONFIG } from "#common/api/config"; import { EVENT_REFRESH } from "#common/constants"; diff --git a/web/src/admin/sources/ldap/LDAPSourceViewPage.ts b/web/src/admin/sources/ldap/LDAPSourceViewPage.ts index c10a3eebf7..d3ada59cdb 100644 --- a/web/src/admin/sources/ldap/LDAPSourceViewPage.ts +++ b/web/src/admin/sources/ldap/LDAPSourceViewPage.ts @@ -3,11 +3,11 @@ import "#admin/sources/ldap/LDAPSourceConnectivity"; import "#admin/sources/ldap/LDAPSourceUserList"; import "#admin/sources/ldap/LDAPSourceGroupList"; import "#admin/events/ObjectChangelog"; +import "#components/sync/SyncStatusCard"; import "#elements/CodeMirror"; import "#elements/Tabs"; import "#elements/buttons/ActionButton/index"; import "#elements/buttons/SpinnerButton/index"; -import "#elements/sync/SyncStatusCard"; import "#elements/tasks/ScheduleList"; import { DEFAULT_CONFIG } from "#common/api/config"; diff --git a/web/src/admin/users/UserViewPage.ts b/web/src/admin/users/UserViewPage.ts index be0f897d36..1f88d45d98 100644 --- a/web/src/admin/users/UserViewPage.ts +++ b/web/src/admin/users/UserViewPage.ts @@ -8,6 +8,8 @@ import "#admin/users/UserChart"; import "#admin/users/UserForm"; import "#admin/users/UserImpersonateForm"; import "#admin/users/UserPasswordForm"; +import "#admin/users/oauth/UserAccessTokenList"; +import "#admin/users/oauth/UserRefreshTokenList"; import "#components/DescriptionList"; import "#components/ak-object-attributes-card"; import "#components/ak-status-label"; @@ -18,8 +20,6 @@ import "#elements/Tabs"; import "#elements/buttons/ActionButton/ak-action-button"; import "#elements/buttons/SpinnerButton/ak-spinner-button"; import "#elements/forms/ModalForm"; -import "#elements/oauth/UserAccessTokenList"; -import "#elements/oauth/UserRefreshTokenList"; import "#elements/user/SessionList"; import "#elements/user/UserConsentList"; import "#elements/user/UserReputationList"; diff --git a/web/src/elements/oauth/UserAccessTokenList.ts b/web/src/admin/users/oauth/UserAccessTokenList.ts similarity index 100% rename from web/src/elements/oauth/UserAccessTokenList.ts rename to web/src/admin/users/oauth/UserAccessTokenList.ts diff --git a/web/src/elements/oauth/UserRefreshTokenList.ts b/web/src/admin/users/oauth/UserRefreshTokenList.ts similarity index 100% rename from web/src/elements/oauth/UserRefreshTokenList.ts rename to web/src/admin/users/oauth/UserRefreshTokenList.ts diff --git a/web/src/components/ak-nav-buttons.ts b/web/src/components/ak-nav-buttons.ts index 7c60f45c40..9639379c2e 100644 --- a/web/src/components/ak-nav-buttons.ts +++ b/web/src/components/ak-nav-buttons.ts @@ -10,10 +10,10 @@ import { formatUserDisplayName } from "#common/users"; import { AKElement } from "#elements/Base"; import { WithNotifications } from "#elements/mixins/notifications"; import { WithSession } from "#elements/mixins/session"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; import { isDefaultAvatar } from "#elements/utils/images"; import Styles from "#components/ak-nav-button.css"; +import { AKDrawerChangeEvent } from "#components/notifications/events"; import { CoreApi } from "@goauthentik/api"; diff --git a/web/src/elements/notifications/APIDrawer.ts b/web/src/components/notifications/APIDrawer.ts similarity index 94% rename from web/src/elements/notifications/APIDrawer.ts rename to web/src/components/notifications/APIDrawer.ts index 807b41977b..84b261c356 100644 --- a/web/src/elements/notifications/APIDrawer.ts +++ b/web/src/components/notifications/APIDrawer.ts @@ -5,7 +5,8 @@ import { globalAK } from "#common/global"; import { AKElement } from "#elements/Base"; import { listen } from "#elements/decorators/listen"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; + +import { AKDrawerChangeEvent } from "#components/notifications/events"; import { msg } from "@lit/localize"; import { css, CSSResult, html, TemplateResult } from "lit"; @@ -80,14 +81,9 @@ export class APIDrawer extends AKElement { @listen(AKRequestPostEvent, { target: window }) protected enqueueRequest = ({ requestInfo }: AKRequestPostEvent) => { - this.requests.push(requestInfo); - - this.requests.sort((a, b) => a.time - b.time).reverse(); - if (this.requests.length > 50) { - this.requests.shift(); - } - - this.requestUpdate(); + this.requests = [requestInfo, ...this.requests] + .toSorted((a, b) => b.time - a.time) + .slice(0, 50); }; render(): TemplateResult { diff --git a/web/src/elements/notifications/NotificationDrawer.ts b/web/src/components/notifications/NotificationDrawer.ts similarity index 99% rename from web/src/elements/notifications/NotificationDrawer.ts rename to web/src/components/notifications/NotificationDrawer.ts index ca690da424..0004eaed27 100644 --- a/web/src/elements/notifications/NotificationDrawer.ts +++ b/web/src/components/notifications/NotificationDrawer.ts @@ -10,10 +10,11 @@ import { formatElapsedTime } from "#common/temporal"; import { AKElement } from "#elements/Base"; import { WithNotifications } from "#elements/mixins/notifications"; import { WithSession } from "#elements/mixins/session"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; import { SlottedTemplateResult } from "#elements/types"; import { ifPresent } from "#elements/utils/attributes"; +import { AKDrawerChangeEvent } from "#components/notifications/events"; + import { Notification } from "@goauthentik/api"; import { msg, str } from "@lit/localize"; diff --git a/web/src/elements/notifications/events.ts b/web/src/components/notifications/events.ts similarity index 95% rename from web/src/elements/notifications/events.ts rename to web/src/components/notifications/events.ts index e40dbaea20..2defce5f8d 100644 --- a/web/src/elements/notifications/events.ts +++ b/web/src/components/notifications/events.ts @@ -1,4 +1,4 @@ -import { DrawerState, readDrawerParams } from "#elements/notifications/utils"; +import { DrawerState, readDrawerParams } from "#components/notifications/utils"; /** * Event dispatched when the state of the interface drawers changes. diff --git a/web/src/elements/notifications/utils.ts b/web/src/components/notifications/utils.ts similarity index 96% rename from web/src/elements/notifications/utils.ts rename to web/src/components/notifications/utils.ts index 23a74b0d2e..4776990cd9 100644 --- a/web/src/elements/notifications/utils.ts +++ b/web/src/components/notifications/utils.ts @@ -2,8 +2,8 @@ * @file Notification drawer utilities. */ -import "#elements/notifications/APIDrawer"; -import "#elements/notifications/NotificationDrawer"; +import "#components/notifications/APIDrawer"; +import "#components/notifications/NotificationDrawer"; import { getURLParam, updateURLParams } from "#elements/router/RouteMatch"; diff --git a/web/src/elements/sync/SyncObjectForm.ts b/web/src/components/sync/SyncObjectForm.ts similarity index 100% rename from web/src/elements/sync/SyncObjectForm.ts rename to web/src/components/sync/SyncObjectForm.ts diff --git a/web/src/elements/sync/SyncStatusCard.stories.ts b/web/src/components/sync/SyncStatusCard.stories.ts similarity index 100% rename from web/src/elements/sync/SyncStatusCard.stories.ts rename to web/src/components/sync/SyncStatusCard.stories.ts diff --git a/web/src/elements/sync/SyncStatusCard.ts b/web/src/components/sync/SyncStatusCard.ts similarity index 100% rename from web/src/elements/sync/SyncStatusCard.ts rename to web/src/components/sync/SyncStatusCard.ts diff --git a/web/src/elements/controllers/NotificationsContextController.ts b/web/src/elements/controllers/NotificationsContextController.ts index a0211a0949..53aba4ef42 100644 --- a/web/src/elements/controllers/NotificationsContextController.ts +++ b/web/src/elements/controllers/NotificationsContextController.ts @@ -13,9 +13,10 @@ import { NotificationsMixin, } from "#elements/mixins/notifications"; import { SessionMixin } from "#elements/mixins/session"; -import { createPaginatedNotificationListFrom } from "#elements/notifications/utils"; import type { ReactiveElementHost } from "#elements/types"; +import { createPaginatedNotificationListFrom } from "#components/notifications/utils"; + import { EventsApi } from "@goauthentik/api"; import { ContextProvider } from "@lit/context"; diff --git a/web/src/elements/controllers/SessionContextController.ts b/web/src/elements/controllers/SessionContextController.ts index 8a72c47365..30e1faadd6 100644 --- a/web/src/elements/controllers/SessionContextController.ts +++ b/web/src/elements/controllers/SessionContextController.ts @@ -20,9 +20,10 @@ import { SessionMixin, UIConfigContext, } from "#elements/mixins/session"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; import type { ReactiveElementHost } from "#elements/types"; +import { AKDrawerChangeEvent } from "#components/notifications/events"; + import { CoreApi, SessionUser } from "@goauthentik/api"; import { setUser } from "@sentry/browser"; diff --git a/web/src/elements/mixins/notifications.ts b/web/src/elements/mixins/notifications.ts index 420f3f08ef..cc15550995 100644 --- a/web/src/elements/mixins/notifications.ts +++ b/web/src/elements/mixins/notifications.ts @@ -4,10 +4,11 @@ import { MessageLevel } from "#common/messages"; import { ContextControllerRegistry } from "#elements/controllers/ContextControllerRegistry"; import { showMessage } from "#elements/messages/MessageContainer"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; -import { createPaginatedNotificationListFrom } from "#elements/notifications/utils"; import { createMixin } from "#elements/types"; +import { AKDrawerChangeEvent } from "#components/notifications/events"; +import { createPaginatedNotificationListFrom } from "#components/notifications/utils"; + import { ConsoleLogger } from "#logger/browser"; import { diff --git a/web/src/user/ak-interface-user.ts b/web/src/user/ak-interface-user.ts index 1977a86c42..327c02fce6 100644 --- a/web/src/user/ak-interface-user.ts +++ b/web/src/user/ak-interface-user.ts @@ -1,7 +1,7 @@ import "#components/ak-nav-buttons"; import "#elements/banner/EnterpriseStatusBanner"; -import "#elements/notifications/APIDrawer"; -import "#elements/notifications/NotificationDrawer"; +import "#components/notifications/APIDrawer"; +import "#components/notifications/NotificationDrawer"; import "#elements/router/RouterOutlet"; import { globalAK } from "#common/global"; @@ -13,15 +13,16 @@ import { AuthenticatedInterface } from "#elements/AuthenticatedInterface"; import { listen } from "#elements/decorators/listen"; import { WithBrandConfig } from "#elements/mixins/branding"; import { canAccessAdmin, WithSession } from "#elements/mixins/session"; -import { AKDrawerChangeEvent } from "#elements/notifications/events"; +import { ifPresent } from "#elements/utils/attributes"; +import { ThemedImage } from "#elements/utils/images"; + +import { AKDrawerChangeEvent } from "#components/notifications/events"; import { DrawerState, persistDrawerParams, readDrawerParams, renderNotificationDrawerPanel, -} from "#elements/notifications/utils"; -import { ifPresent } from "#elements/utils/attributes"; -import { ThemedImage } from "#elements/utils/images"; +} from "#components/notifications/utils"; import Styles from "#user/ak-interface-user.css"; import { ROUTES } from "#user/Routes"; diff --git a/website/Dockerfile b/website/Dockerfile index 6e219637f4..e47d6520f8 100644 --- a/website/Dockerfile +++ b/website/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=${BUILDPLATFORM} docker.io/library/node:25.9.0-trixie@sha256:e588aafb1146d1dfdc9227195d4fb779fba528b2b937ac5b729a0c269cfb7595 AS docs-builder +FROM --platform=${BUILDPLATFORM} docker.io/library/node:26.2.0-trixie@sha256:980c5420a7a2ddcb44037726977f2a349e5c7b64217516c7488dce4c74d71583 AS docs-builder ENV NODE_ENV=production @@ -47,7 +47,7 @@ COPY ./SECURITY.md /work/ RUN --mount=type=bind,target=/work/packages/docusaurus-config/,src=./packages/docusaurus-config/ \ corepack npm run build -w docs -FROM docker.io/library/nginx:1.29-trixie@sha256:1881968aff6f7cdcc4b888c00a11f4ce241ad7ec957e0cb4a9e19e93a3ff87ea +FROM docker.io/library/nginx:1.31-trixie@sha256:800e7c98538c6bf725f5177e841aa720ae0ed1c378bbea368b6330bfe18a36b3 LABEL org.opencontainers.image.authors="Authentik Security Inc." \ org.opencontainers.image.source="https://github.com/goauthentik/authentik" \ org.opencontainers.image.description="authentik product documentation" \ diff --git a/website/docs/users-sources/sources/protocols/saml/index.md b/website/docs/users-sources/sources/protocols/saml/index.md index d3fe8cef57..43703db091 100644 --- a/website/docs/users-sources/sources/protocols/saml/index.md +++ b/website/docs/users-sources/sources/protocols/saml/index.md @@ -29,6 +29,7 @@ If you have the provider metadata, you should be able to extract all values you | Issuer/Entity ID | https://authentik.company | The identifier for the authentik instance in the SAML federation, can be chosen freely. This is used to identify the SP on the IDP side, it usually makes sense to configure this to the URL of the SP or the path corresponding to the SP (e.g. `/source/saml//` | | Binding Type | HTTP-POST | How authentik communicates with the SSO URL (302 redirect or POST request). This will depend on what the provider supports. | | Allow IDP-Initiated Logins | False | Whether to allow the IDP to log users into authentik without any interaction. Activating this may constitute a security risk since this request is not verified, and could be utilized by an attacker to authenticate a user without interaction on their side. | +| Force authentication | False | When enabled, authentik requests the IDP to force re-authentication of the user, even if they already have an active session with the IDP. | | NameID Policy | Persistent | Depending on what the IDP sends as persistent ID, some IDPs use the username or email address while others will use a random string/hashed value. If the user in authentik receives a random string as a username, try using Email address or Windows | | Flow settings | Default | If there are custom flows in your instance for external authentication, change to use them here | diff --git a/website/integrations/device-management/apple/index.md b/website/integrations/device-management/apple/index.md index 76a221cc8d..5a259e2680 100644 --- a/website/integrations/device-management/apple/index.md +++ b/website/integrations/device-management/apple/index.md @@ -15,7 +15,7 @@ authentik_preview: true ## What is Apple Business Manager? -> Apple Business Manager is a web-based portal for IT administrators, managers, and procurement professionals to manage devices, and automate device enrollment. +> Apple Business Manager is a web-based portal for IT administrators, managers, and procurement professionals to manage devices and automate device enrollment. > > Organizations using Apple Business Essentials can allow their users to authenticate into their Apple devices using their IdP credentials, typically their company email addresses. > @@ -35,7 +35,7 @@ While this integration guide focuses on Business Manager, the instructions are a ## Authentication flow -This sequence diagram shows a high-level flow between the user's apple device, authentik, and Apple Business Manager. +This sequence diagram shows a high-level flow between Apple device, authentik, and Apple Business Manager. ```mermaid sequenceDiagram @@ -53,8 +53,7 @@ sequenceDiagram ``` -In short, Apple Business Manager recognizes the email domain -as a federated identity provider controlled by authentik. When a user signs in with their email address, Apple redirects them to authentik for authentication. Once authenticated, Apple enrolls the user's device and grants access to Apple services. +In short, Apple Business Manager recognizes the email domain as a federated identity provider controlled by authentik. When a user signs in with their email address, Apple redirects them to authentik for authentication. Once authenticated, Apple enrolls the user's device and grants access to Apple services. ## Preparation @@ -62,21 +61,13 @@ By the end of this integration, your users will be able to enroll their Apple de You'll need to have an authentik instance running and accessible on an HTTPS domain, and an Apple Business Manager user with the role of Administrator or People Manager. -:::warning Caveats - +:::warning Apple Business Manager restrictions Be aware that Apple Business Manager imposes the following restrictions on federated authentication: - Federated authentication should use the user’s email address as their username. Aliases aren’t supported. - Existing users with an email address in the federated domain will automatically be converted to federated authentication, effectively _taking ownership_ of the account. - User accounts with the role of Administrator, Site Manager, or People Manager can’t sign in using federated authentication; they can only manage the federation process. - -::: - -### Placeholders - -The following placeholders are used in this guide: - -- `authentik.company`: The FQDN of the authentik installation. + ::: ## authentik configuration @@ -94,18 +85,18 @@ Apple Business Manager requires that we create three scope mappings for our OIDC #### User profile information -1. From the authentik Admin interface, navigate to **Customization > Property Mappings** and click **Create**. +Apple Business Manager requires both a given name and family name in the OIDC claim. The example expression below assumes that the user's name is formatted with the given name first, followed by the family name, delimited by a space. -2. Select **Scope Mapping** and use the following values: +Consider adjusting the expression to match the name format used in your organization. + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Property Mappings** and click **Create**. +3. Select **Scope Mapping** and set the following values: - **Name**: `Apple Business Manager profile` - **Scope Name**: `profile` - - **Description**: _[optional]_ Set to inform user - **Expression**: - Apple Business Manager requires both a given name and family name in the OIDC claim. The example expression below assumes that the user's name is formatted with the given name first, followed by the family name, delimited by a space. - Consider adjusting the expression to match the name format used in your organization. - - ```py + ```python given_name, _, family_name = request.user.name.partition(" ") return { @@ -114,151 +105,128 @@ Apple Business Manager requires that we create three scope mappings for our OIDC } ``` -3. Click **Finish** and confirm that new scope mapping is listed in the **Property Mappings** overview. +4. Click **Finish**. #### Read access -1. On the **Property Mappings** list, click **Create**. - -2. Select **Scope Mapping** and use the following values: +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Property Mappings** and click **Create**. +3. Select **Scope Mapping** and set the following values: - **Name**: `Apple Business Manager ssf.read` - **Scope Name**: `ssf.read` - - **Description**: _[optional]_ Set to inform user - **Expression**: `return {}` -3. Click **Finish** and confirm that new scope mapping is listed in the **Property Mappings** overview. +4. Click **Finish**. #### Management access -1. On the **Property Mappings** list, click **Create**. - -2. Select **Scope Mapping** and use the following values: +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Property Mappings** and click **Create**. +3. Select **Scope Mapping** and set the following values: - **Name**: `Apple Business Manager ssf.manage` - **Scope Name**: `ssf.manage` - - **Description**: _[optional]_ Set to inform user - **Expression**: `return {}` -3. Click **Finish** and confirm that new scope mapping is listed in the **Property Mappings** overview. +4. Click **Finish**. -### 2. Create signing keys +### 2. Create signing key -You will need to create **Signing Key** to sign Security Event Tokens (SET). +You will need to create a **Signing Key** to sign Security Event Tokens (SET). This key is used to both sign and verify the SETs that are sent between authentik and Apple Business Manager. -You can either generate a new key or import an existing one. +You can either generate a new key or import an existing one. It is recommended to use the same key for both the OIDC and SSF providers. #### Generate a new key -1. From the Admin interface, navigate to **System > Certificates** -2. Click **Generate**, select **Signing Key**, and use the following values: - - **Common Name**: `apple-business-manager` - -3. Click **Generate** and confirm that the new key is listed in the **Certificates** overview. +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **System** > **Certificates** and click **Generate Certificate-Key Pair**. +3. Provide a **Certificate Name** and click **Generate Certificate-Key Pair**. #### Import an existing key -Alternatively, you can use an existing key if you have one available. +Alternatively, you can import an existing key. -1. From the Admin interface, navigate to **System > Certificates**. -2. Click **Create** and use the following values: - - **Name**: `apple-business-manager` - - **Certificate**: Paste in your certificate - - **Private Key**: _[optional]_ Paste in your private key - -3. Click **Create** and confirm that the new key is listed in the **Certificates** overview. +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **System** > **Certificates** and click **Import Existing Certificate-Key Pair**. +3. Provide a **Certificate Name**, paste the contents of your **Certificate**. +4. Click **Import Certificate-Key Pair**. ### 3. Create OIDC provider -:::tip Keep your text editor ready +You will need to create an [OAuth2/OpenID Provider](/docs/add-secure-apps/providers/oauth2/) to handle the authentication flow between authentik and Apple Business Manager. -authentik will automatically generate the **Client ID** and **Client Secret** values for the new provider. You'll need these values when configuring Apple Business Manager. +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Providers** and click **New Provider** to open the provider wizard. + - **Choose a Provider type**: select **OAuth2/OpenID Provider** as the provider type. + - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. + - Note the **Client ID** and **Client Secret** values because they will be required later. + - Set a `Strict` redirect URI to `https://gsa-ws.apple.com/grandslam/GsService2/acs`. + - Select any available signing key. + - Under **Advanced protocol settings**, in addition to the default scopes, add the four following **Selected Scopes** to the provider. + - `Apple Business Manager ssf.manage` + - `Apple Business Manager ssf.read` + - `Apple Business Manager profile` + - `authentik default OAuth Mapping: OpenID 'offline_access'` -You can always find your provider's generated values by navigating to **Providers**, selecting the provider by name, and clicking the **Edit** button. - -::: - -1. From the authentik Admin interface, navigate to **Applications > Providers** and click **Create**. -2. For the **Provider Type** select **OAuth2/OpenID Provider**, click **Next**, and use the following values. - - **Name**: `Apple Business Manager` - - **Authorization flow**: Select a flow that suits your organization's requirements. - - **Protocol settings**: - - **Client ID**: Copy the generated value to your text editor. - - **Client Secret**: Copy the generated value to your text editor. - - **Redirect URIs/Origins**: - - `Strict` - - **URL**: `https://gsa-ws.apple.com/grandslam/GsService2/acs` - - **Signing Key**: Select a certificate to sign the OpenID Connect tokens. - - **Advanced protocol settings**: - Any fields that can be left as their default values are omitted from the list. - - **Scopes**: Add four **Selected Scopes** to the provider. - - [x] `Apple Business Manager ssf.manage` - - [x] `Apple Business Manager ssf.read` - - [x] `Apple Business Manager profile` - - [x] `authentik default OAuth Mapping: OpenID 'profile'` - -3. Click **Finish** and confirm that `Apple Business Manager` is listed in the provider overview. - -4. Navigate to **Applications > Providers** and click `Apple Business Manager`. -5. Copy the **OpenID Configuration URL** field to your text editor. +3. Click **Create**. ### 4. Create Shared Signals Framework provider While the OIDC provider handles the authentication flow, you'll need to create a [Shared Signals Framework provider](/docs/add-secure-apps/providers/ssf/) to handle the backchannel communication between authentik and Apple Business Manager. -1. From the authentik Admin interface, navigate to **Applications > Providers** and click **Create**. -2. Select **Shared Signals Framework Provider** and use the following values. - Any fields that can be left as their default values are omitted from the list. - - **Name** `Apple Business Manager SSF` - - **Signing Key**: `[Your Signing Key]` - - **Event Retention**: `days=30` +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Providers** and click **New Provider** to open the provider wizard. + - **Choose a Provider type**: select **Shared Signals Framework Provider** and the provider type. + - **Configure the Provider**: provide a name (or accept the auto-provided name), and the following required configurations. + - Select the same signing key that you selected for the OIDC provider. -3. Click **Finish** and confirm that the new SSF provider is listed in the overview. +3. Click **Create**. - :::tip A blank SSF Config URL is expected - - Keep in mind the **SSF Config URL** will be blank until the SSF provider is assigned to an application as a backchannel provider. We'll return to collect this URL after creating the application. - - ::: +:::note A Blank SSF Config URL is expected +The **SSF Config URL** will be blank until the SSF provider is assigned to an application as a backchannel provider. +::: ### 5. Assign SSF permissions -The authentik user you will use to test the stream connection to Apple Business Manager must either have the role of superuser or have permission to add streams to the SSF provider. +The authentik user you will use to test the stream connection to Apple Business Manager must either be a member of the authentik Admins group (such as the default `akadmin` account) or have permission to **Add stream to SSF provider**. -1. From authentik the Admin interface, navigate to **Applications > Providers** and click the Apple Business Manager SSF provider. +If not using a superuser account, you can assign the correct permission by following these steps: -2. Click the **Permissions** tab, select **User Object Permissions**, and click **Assign to new user**. - -3. In the **User** field, enter the object name of the test user performing the initial connection to Apple Business Manager. - -4. Set the **Add stream to SSF provider** permission toggle to **On** - -5. Click **Assign** and confirm that the user is listed in the **User Object Permissions** list. +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Directory** > **Roles** and click **New Role**. +3. Provide a name for the new role and click **Create Role**. +4. Click on the name of the newly created role and open the **Users** tab. +5. Add whichever user you want to have the permission. +6. Navigate to **Applications** > **Providers** and click on the name of the SSF provider. +7. Open the **Permissions** tab and click **Assign Role Object Permission**. +8. Select the newly created role, toggle on **Add stream to SSF provider**, and click **Assign Role Object Permission**. ### 6. Create application -1. From the authentik Admin interface, navigate to **Applications > Applications**, click **Create**, and use the following values: - - **Name**: Apple Business Manager +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Application**, click the **New Application** dropdown, click **with Existing Provider**, and set the following required values: + - **Application Name**: `Apple Business Manager` - **Slug**: `abm` - - **Provider**: `Apple Business Manager` - - **Backchannel Provider:** `Apple Business Manager SSF` + - **Provider**: Select the OIDC provider that you created + - **Backchannel Provider:** Select the SSF provider that you created -2. Click **Create** and confirm that the application is listed in the overview page. - -3. Navigate to **Providers > Apple Business Manager SSF** - - On the **Overview** tab copy the `SSF Config URL` value to your text editor. +3. Click **Create application**. +4. Navigate to **Application** > **Providers** and click on the name of the SSF provider. +5. On the **Overview** tab, take note of the **SSF Config URL** value. +6. Navigate to **Application** > **Providers** and click on the name of the OIDC provider. +7. On the **Overview** tab, take note of the **OpenID Configuration URL** value. ### 7. Confirm and modify copied authentik values -Before proceeding to Apple Business Manager, let's go over the values that you have copied from authentik. +Before proceeding to Apple Business Manager, ensure that you have noted the following values from authentik: -- Verify that you have all the necessary values in your text editor: - - From the `Apple Business Manager` provider: - - [x] `Client ID` - - [x] `Client Secret` - - [x] `OpenID Configuration URL` + - From the OIDC provider: + - Client ID + - Client Secret + - OpenID Configuration URL - - From the `Apple Business Manager SSF` provider: - - [x] `SSF Config URL` + - From the SSF provider: + - SSF Config URL ## Apple Business Manager configuration @@ -270,67 +238,58 @@ Similar to a personal Apple account, a _Managed Apple Account_ uses an email add By verifying the domain, Apple Business Manager will delegate ownership of any accounts with a matching email address to the organization, allowing for centralized management of devices, apps, and services. -1. From the [Apple Business Manager dashboard](https://business.apple.com/), click **your account name** on the sidebar, then select **Preferences**. - -2. From the Preferences page, select **Managed Apple Accounts** tab, click **Add Domain** and then provide your domain name. +1. Log in to the [Apple Business Manager dashboard](https://business.apple.com/) as an administrator. +2. Click your account name in the sidebar, then select **Preferences**. +3. From the Preferences page, select **Managed Apple Accounts** tab, click **Add Domain**, and then provide your domain name. Apple will generate a DNS TXT record that you'll need to add to your domain's DNS settings. - -3. Wait for DNS propagation and click **Verify** to complete the domain verification process. +4. Wait for DNS propagation and click **Verify** to complete the domain verification process. A confirmation dialog will prompt you to lock your domain before you can proceed with the next steps. :::warning Locking your domain affects all enrolled users - Locking your domain ensures that only your organization can use your domain for federated authentication. **Once locked, your enrolled users will not be able to access Apple services until you complete the next steps to configure federated authentication.** **Only lock your domain when you're ready to proceed with the next steps.** - ::: -4. In the confirmation dialog, set the **Lock Domain** toggle to **On** and confirm that the domain displays as locked in the **Managed Apple Accounts** tab. +5. In the confirmation dialog, set the **Lock Domain** toggle to **On** and confirm that the domain displays as locked in the **Managed Apple Accounts** tab. -### 2. Capture all accounts +### 2. Capture all accounts _(optional)_ Optionally, you may choose to [capture all accounts](https://support.apple.com/guide/apple-business-manager/capture-a-domain-axm512ce43c3/1/web/1), which will convert all existing accounts with an email address in the federated domain to _Managed Apple Accounts_. You can also choose to capture all accounts at a later time when you're ready to manage all users in the domain. :::danger Account capture is one-way migration - Choosing to capture all accounts will affect all users with an email address in the federated domain, regardless of their enrollment status or device ownership. **Once captured, the accounts can't be reverted to personal Apple accounts – even if the domain is unlocked.** **Only capture accounts if you're sure that every user in the domain should be managed by Apple Business Manager.** - ::: -1. From the [Apple Business Manager dashboard](https://business.apple.com/), click **your account name** on the sidebar, then select **Preferences**. - -2. From the Preferences page, select **Managed Apple Accounts** tab, and click **Manage** next to the domain you've verified. - -3. In your domain's management dialog, ensure you understand the implications of capturing all accounts and then click **Capture All Accounts**. - -4. Wait for Apple to complete the account capture process, and confirm that all accounts are now managed by Apple Business Manager. +1. Log in to the [Apple Business Manager dashboard](https://business.apple.com/) as an administrator. +2. Click **your account name** in the sidebar, then select **Preferences**. +3. From the Preferences page, select **Managed Apple Accounts** tab, and click **Manage** next to the domain you've verified. +4. In your domain's management dialog, ensure you understand the implications of capturing all accounts and then click **Capture All Accounts**. +5. Wait for Apple to complete the account capture process, and confirm that all accounts are now managed by Apple Business Manager. ### 3. Enable federated authentication You're now ready to configure federated authentication with authentik. -1. From the Apple Business Manager dashboard, click **your account name** on the sidebar, then select **Preferences**. - -2. From the Preferences page, select **Managed Apple Accounts** tab, and click **Get Started** under the "User sign in and directory sync" section. - -3. To define how you want users to sign in, choose **Custom Identity Provider** and click **Continue**. - -4. On the **Set up your Custom Identity Provider** page, use the following values: +1. Log in to the [Apple Business Manager dashboard](https://business.apple.com/) as an administrator. +2. Click **your account name** in the sidebar, then select **Preferences**. +3. From the Preferences page, select **Managed Apple Accounts** tab, and click **Get Started** under the **User sign in and directory sync** section. +4. To define how you want users to sign in, choose **Custom Identity Provider** and click **Continue**. +5. On the **Set up your Custom Identity Provider** page, use the following values: - **Name**: `authentik` - - **Client ID**: _`Your Client ID`_ - - **Client Secret**: _`Your Client Secret`_ - - **SSF Config URL**: **_`Your SSF Config URL with 443 port`_** - - **OpenID Config URL**: **_`Your OpenID Config URL with 443 port`_** + - **Client ID**: Client ID from authentik + - **Client Secret**: Client Secret from authentik + - **SSF Config URL**: SSF Config URL from authentik + - **OpenID Config URL**: OpenID Configuration URL from authentik -5. Click **Continue** to begin Apple's verification of your configuration. -6. When prompted to authenticate through your authentik instance, provide your credentials and click **Log In**. +6. Click **Continue** to begin Apple's verification of your configuration. +7. When prompted to authenticate through your authentik instance, provide your credentials and click **Log In**. When the test finishes, click **Done** to complete the configuration. @@ -342,18 +301,17 @@ If the connection test fails, your configuration may be incorrect. Here are some - [x] Verify that the Client ID and Client Secret values are correct. - [x] Verify that scope mappings are created and all assigned to the OIDC provider. - [x] Verify that the SSF provider is assigned to the application. -- [x] Ensure that the SSF Config URL and OpenID Configuration URL include the port number `443`. +- [x] Ensure that the SSF Config URL and OpenID Configuration URL are accurate. +- [x] Ensure that the OAuth and SSF providers both have signing keys set. Ideally the same certificate should be used for both. If you're still having issues, check your authentik instance's log for any errors that might have occurred during the authentication process. If Apple can reach your authentik instance, you should see logs indicating Apple's attempts to test the authentication flow. ## Configuration verification :::warning Administrators cannot use federated authentication - Apple Business Manager does not allow users with the role of Administrator, Site Manager, or People Manager to log in using federated authentication. When creating test users, ensure that their role is set to Standard (or Student) to test federated authentication with authentik. - ::: ### 1. Create a test user @@ -366,17 +324,14 @@ When creating test users, ensure that their role is set to Standard (or Student) - **Role**: `Standard` 3. Click **Save** to create the user account, and then click **Create Sign-In** in the user's profile. - 4. When prompted to choose a delivery method, select **Create a downloadable PDF and CSV** and click **Continue**. Note the temporary password provided on the next page, optionally downloading the PDF and CSV files for future reference. - 5. Confirm the user is created from the authentik Admin interface by navigating to the **Users** page and searching for the account by their email address. Note that this may take a few minutes to synchronize. ### 2. Test the authentication flow -1. Confirmed the test user in synchronized in authentik. +1. Confirm that the test user is synchronized in authentik. 2. Open a private browsing window and navigate to the [Apple Business Manager](https://business.apple.com/). -3. In the email field, provide the email address assigned to test user. - +3. In the email field, provide the email address assigned to the test user. 4. Submit the form to trigger the authentication flow. You should be redirected to authentik for authentication and then back to Apple Business Manager to manage the test user's account.