v5.1.0
After the first release of this fork, I decided to change the versioning scheme for the variants to bring it more in line with the standard. Given that Jellyfin is also changing its versioning scheme, i decided to make this change now. Therefore, from now on, each version will follow the semantic versioning scheme, which uses a three-part version number format: MAJOR.MINOR.PATCH
(Jellyfin will use a different two-digit versioning scheme, but I think it's better to use the standard three-digit scheme for this project)
Jellyfin 12 support
This version targets Jellyfin >= 12.0 and requires it: the plugin is now built on
.NET 10 against the Jellyfin 12.0.0 packages, with targetAbi 12.0.0.0. If you run
Jellyfin 10.8 – 10.11, stay on plugin version 5.0.0.0.
- Retargeted the plugin to .NET 10 and Jellyfin 12.0.0 (version bumped to 5.1.0).
- Fixed account linking on Jellyfin 12: Jellyfin 12 disables legacy authorization by
default, so theX-Emby-Authorizationheader was ignored and the linking flow failed
with 401. The linking page and the bundled API client now send the token through the
modernAuthorizationheader, keeping the legacy one for older servers. - The
api_keyquery parameter is replaced byApiKey(the only accepted casing when
legacy authorization is disabled) throughout the documentation. - CI (build, test, publish, nightly) now builds with .NET 10.
Security: SSO accounts can no longer be signed into without SSO
Jellyfin accepts the empty password on the ordinary login form for any account that
has no stored password, so accounts created or linked through SSO were reachable with
just the username. This is now closed in three places, all sharing one password mint:
- At provisioning, the account's provider routing and an unguessable password (64
bytes from the OS CSPRNG) are written as soon as the account exists. If that write
fails, the half-created account is removed again so a failed login cannot leave a
password-less account behind. - At login, a linked account that still holds no stored password is sealed before
the session is created. - At start-up, a one-shot pass walks every canonical link of every provider (OID and
SAML) and seals each linked account with no password. It never changes login routing,
never overwrites an existing password, and is idempotent.
When accounts are sealed, the log carries a [SSO Audit] Sealed N SSO-linked account(s) that had no stored password line with a count only. This closes #50.
Many thanks to @aslafy-z and everyone who reported this or tried to fix the problem for their help in resolving this issue: the root-cause analysis of the missing password persistence, the fail-closed account creation and the login-time sealing all build on their work in https://github.com/aslafy-z/jellyfin-plugin-sso/pull/1.
New features
- PreserveAdminPermissions option (#14): when enabled, SSO can elevate users to
administrator from admin roles but will not revoke the administrator flag from an
account that already has it. By default SSO remains the strict source of truth. - OpenID scope overrides and custom authorization parameters (#37):
OverrideDefaultScopes
andOidAuthorizationParameterslet providers with non-standard flows be configured. - Content download permission management (#39):
EnableContentDownloadingand
ApplyContentDownloadPermissionOnEveryLogincontrol the download permission in the
SSO flow, for new users and optionally on every login. - French (fr) locale (#34), with translation-completeness tests keeping locales in
sync (#38).
Fixes
- User provisioning now persists the provider routing and password through
UpdateUserAsync, and permission changes go through Jellyfin's user policy path, which
preserves access schedules and lyric management reliably on current Jellyfin versions (#15). - Newly created users with authorization disabled start with no folder access instead of
Jellyfin's defaults (#18). - Null
Roles/AdminRolesin provider configurations no longer throw null-reference
exceptions (#16, #17). - Fixed provider checkbox handling in the configuration page (#13).
Internal
- Extracted
AuthorizationEvaluatorfrom the controller and covered OIDC/SAML RBAC with
tests (#26); added tests for the OIDC scope and authorization parameter builders (#37),
the content download policy (#39), and the password sealing (76 tests total). StateManagernow uses aConcurrentDictionaryfor thread safety (#27).- Removed the unused F# library leftover from the original project (#19) and modernized
the CI workflows (#21).
What's Changed
- fix: improve provider checkbox handling in configuration page by @K0lin in #13
- feat: add PreserveAdminPermissions option to manage admin roles in SSO authentication by @K0lin in #14
- fix: enhance user permission management and error handling in SSOController by @K0lin in #15
- fix: handle null roles in SSOController to prevent potential errors by @K0lin in #16
- fix: handle null config roles in SSOController to prevent potential null reference exceptions by @K0lin in #17
- fix: add enableAuthorization parameter to CreateCanonicalLinkAndUserIfNotExist for improved user policy management by @K0lin in #18
- remove unused Library.fs by @K0lin in #19
- modernize CI tooling by @K0lin in #21
- test: add AuthorizationEvaluator coverage for OIDC and SAML RBAC by @K0lin in #26
- refactor: replace IDictionary with ConcurrentDictionary for StateManager to improve thread safety by @K0lin in #27
- chore(deps): update dependency newtonsoft.json to 13.0.4 by @renovate[bot] in #28
- chore(deps): update dependency prettier to v3.9.1 by @renovate[bot] in #30
- chore(deps): update dependency microsoft.net.test.sdk to v18 by @renovate[bot] in #31
- chore(deps): update dependency system.security.cryptography.xml to 6.0.2 by @renovate[bot] in #29
- chore(deps): update github actions by @renovate[bot] in #33
- chore(deps): update github actions (major) by @renovate[bot] in #32
- chore(deps): update dependency prettier to v3.9.5 by @renovate[bot] in #35
- i18n: add French (fr) locale by @flowcool in #34
- feat(oidc): add scope overrides and custom authorization parameters by @K0lin in #37
- test(i18n): add translation completeness tests for locale validation by @K0lin in #38
- feat(content-download): implement content download permission management in SSO flow by @K0lin in #39
- chore(deps): update dependency prettier to v3.9.6 by @renovate[bot] in #42
- chore(deps): update github actions by @renovate[bot] in #40
- chore(deps): update dependency microsoft.net.test.sdk to 18.8.1 by @renovate[bot] in #41
- chore(deps): update dependency duende.identitymodel.oidcclient to v7 by @renovate[bot] in #43
- chore(deps): update dependency system.security.cryptography.xml to v10 by @renovate[bot] in #44
- chore(deps): update dependency microsoft.net.test.sdk to 18.9.0 by @renovate[bot] in #47
- chore(deps): update dependency system.security.cryptography.xml to 10.0.11 by @renovate[bot] in #46
- feat: add Jellyfin 12 support (.NET 10, modern Authorization header) by @K0lin in #52
- fix: seal password-less SSO-linked accounts against empty-password login by @K0lin in #54
New Contributors
Full Changelog: v5.0.0.0...v5.1.0