fix: admin role mapping grants only, revoke behind opt-in
SSO login for an existing admin whose token lacked the admin role was silently demoting the account, locking admins out of the dashboard. Missing admin role now leaves the flag alone unless RevokeAdminWithoutRole is enabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -143,9 +143,16 @@ public class OidcAuthController : ControllerBase
|
|||||||
var adminRoles = SplitCsv(Config.AdminRoles);
|
var adminRoles = SplitCsv(Config.AdminRoles);
|
||||||
if (adminRoles.Length > 0)
|
if (adminRoles.Length > 0)
|
||||||
{
|
{
|
||||||
var isAdmin = roles.Intersect(adminRoles, StringComparer.OrdinalIgnoreCase).Any();
|
var hasAdminRole = roles.Intersect(adminRoles, StringComparer.OrdinalIgnoreCase).Any();
|
||||||
_logger.LogInformation("OIDC admin mapping for {Username}: admin roles [{AdminRoles}] => admin={IsAdmin}", username, Config.AdminRoles, isAdmin);
|
_logger.LogInformation("OIDC admin mapping for {Username}: admin roles [{AdminRoles}] => hasAdminRole={HasAdminRole}", username, Config.AdminRoles, hasAdminRole);
|
||||||
user.SetPermission(PermissionKind.IsAdministrator, isAdmin);
|
if (hasAdminRole)
|
||||||
|
{
|
||||||
|
user.SetPermission(PermissionKind.IsAdministrator, true);
|
||||||
|
}
|
||||||
|
else if (Config.RevokeAdminWithoutRole)
|
||||||
|
{
|
||||||
|
user.SetPermission(PermissionKind.IsAdministrator, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ public class PluginConfiguration : BasePluginConfiguration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string AllowedRoles { get; set; } = string.Empty;
|
public string AllowedRoles { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether a missing admin role also revokes an
|
||||||
|
/// existing administrator flag on OIDC login. Off by default: admin roles only grant.
|
||||||
|
/// </summary>
|
||||||
|
public bool RevokeAdminWithoutRole { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether unknown users are created on first login.
|
/// Gets or sets a value indicating whether unknown users are created on first login.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -51,6 +51,13 @@
|
|||||||
<div class="fieldDescription">Comma separated. Users with one of these roles become Jellyfin administrators. Empty = never touch admin flag.</div>
|
<div class="fieldDescription">Comma separated. Users with one of these roles become Jellyfin administrators. Empty = never touch admin flag.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||||
|
<label class="emby-checkbox-label">
|
||||||
|
<input is="emby-checkbox" id="RevokeAdminWithoutRole" type="checkbox" />
|
||||||
|
<span>Also revoke admin when the admin role is missing (careful: can demote your existing admin account on SSO login)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||||
<label class="emby-checkbox-label">
|
<label class="emby-checkbox-label">
|
||||||
<input is="emby-checkbox" id="CreateUsersIfMissing" type="checkbox" />
|
<input is="emby-checkbox" id="CreateUsersIfMissing" type="checkbox" />
|
||||||
@@ -90,7 +97,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var pluginId = '96badb44-9940-4ff0-befc-5f987159152c';
|
var pluginId = '96badb44-9940-4ff0-befc-5f987159152c';
|
||||||
var textFields = ['OidIssuer', 'OidClientId', 'OidClientSecret', 'OidScopes', 'UsernameClaim', 'RoleClaim', 'AllowedRoles', 'AdminRoles'];
|
var textFields = ['OidIssuer', 'OidClientId', 'OidClientSecret', 'OidScopes', 'UsernameClaim', 'RoleClaim', 'AllowedRoles', 'AdminRoles'];
|
||||||
var boolFields = ['CreateUsersIfMissing', 'SetRandomPasswordOnCreate', 'DisableEndpointValidation'];
|
var boolFields = ['RevokeAdminWithoutRole', 'CreateUsersIfMissing', 'SetRandomPasswordOnCreate', 'DisableEndpointValidation'];
|
||||||
|
|
||||||
document.querySelector('#OidcAuthConfigPage').addEventListener('pageshow', function () {
|
document.querySelector('#OidcAuthConfigPage').addEventListener('pageshow', function () {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<RootNamespace>Jellyfin.Plugin.OidcAuth</RootNamespace>
|
<RootNamespace>Jellyfin.Plugin.OidcAuth</RootNamespace>
|
||||||
<AssemblyVersion>1.0.2.0</AssemblyVersion>
|
<AssemblyVersion>1.0.3.0</AssemblyVersion>
|
||||||
<FileVersion>1.0.2.0</FileVersion>
|
<FileVersion>1.0.3.0</FileVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ Then in Jellyfin: Dashboard → Plugins → OIDC Auth:
|
|||||||
| Username claim | Default `preferred_username`, falls back to `sub` |
|
| Username claim | Default `preferred_username`, falls back to `sub` |
|
||||||
| Role claim | Default `groups` |
|
| Role claim | Default `groups` |
|
||||||
| Allowed roles | CSV; empty = every authenticated user may log in |
|
| Allowed roles | CSV; empty = every authenticated user may log in |
|
||||||
| Admin roles | CSV; empty = plugin never touches the admin flag |
|
| Admin roles | CSV; users with one of these roles are granted admin on SSO login. Missing role does **not** revoke admin unless "Also revoke admin" is enabled. Empty = plugin never touches the admin flag |
|
||||||
| Create users on first login | On by default; new users get access to all libraries |
|
| Create users on first login | On by default; new users get access to all libraries |
|
||||||
| Set random password for auto-created users | On by default. Without it, Jellyfin accepts a **blank password** for these users from any client — convenient on a LAN-only server, dangerous on an exposed one |
|
| Set random password for auto-created users | On by default. Without it, Jellyfin accepts a **blank password** for these users from any client — convenient on a LAN-only server, dangerous on an exposed one |
|
||||||
| Disable strict endpoint validation | Enable for Google and other providers whose endpoints are on a different host than the issuer |
|
| Disable strict endpoint validation | Enable for Google and other providers whose endpoints are on a different host than the issuer |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: "OIDC Auth"
|
name: "OIDC Auth"
|
||||||
guid: "96badb44-9940-4ff0-befc-5f987159152c"
|
guid: "96badb44-9940-4ff0-befc-5f987159152c"
|
||||||
version: "1.0.1.0"
|
version: "1.0.3.0"
|
||||||
targetAbi: "10.11.0.0"
|
targetAbi: "10.11.0.0"
|
||||||
framework: "net9.0"
|
framework: "net9.0"
|
||||||
owner: "pascallinxweiler"
|
owner: "pascallinxweiler"
|
||||||
|
|||||||
BIN
dist/oidc-auth_1.0.3.0.zip
vendored
Normal file
BIN
dist/oidc-auth_1.0.3.0.zip
vendored
Normal file
Binary file not shown.
@@ -7,6 +7,14 @@
|
|||||||
"owner": "pascallinxweiler",
|
"owner": "pascallinxweiler",
|
||||||
"category": "Authentication",
|
"category": "Authentication",
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.0.3.0",
|
||||||
|
"changelog": "Admin role mapping now only grants admin by default. New opt-in setting 'Also revoke admin when the admin role is missing' restores the old revoking behavior.",
|
||||||
|
"targetAbi": "10.11.0.0",
|
||||||
|
"sourceUrl": "https://git.linxweiler.xyz/pascallinxweiler/jellyfinplugin/raw/branch/main/dist/oidc-auth_1.0.3.0.zip",
|
||||||
|
"checksum": "8e1435d2d4a1587797f9c0af53f6fca2",
|
||||||
|
"timestamp": "2026-07-13T13:00:00Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.2.0",
|
"version": "1.0.2.0",
|
||||||
"changelog": "Log OIDC claims and admin mapping decisions; role comparison is now case-insensitive.",
|
"changelog": "Log OIDC claims and admin mapping decisions; role comparison is now case-insensitive.",
|
||||||
|
|||||||
Reference in New Issue
Block a user