200 lines
7.2 KiB
C#
200 lines
7.2 KiB
C#
namespace Jellyfin.Plugin.OIDC_Auth;
|
|
|
|
/// <summary>
|
|
/// Plugin Configuration.
|
|
/// </summary>
|
|
public class PluginConfiguration : MediaBrowser.Model.Plugins.BasePluginConfiguration {
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PluginConfiguration" /> class.
|
|
/// </summary>
|
|
public PluginConfiguration() {
|
|
this.Configs = new SerializableDictionary<string, Config>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the OpenID configurations available.
|
|
/// </summary>
|
|
[System.Xml.Serialization.XmlElementAttribute("Configs")]
|
|
public SerializableDictionary<string, Config> Configs { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The configuration required for a OpenID flow.
|
|
/// </summary>
|
|
[System.Xml.Serialization.XmlRootAttribute("PluginConfiguration")]
|
|
public class Config {
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Config"/> class.
|
|
/// </summary>
|
|
public Config() {
|
|
this.Enabled = false;
|
|
this.Scopes = ["profile", "groups"];
|
|
this.UsernameClaim = "preferred_username";
|
|
this.RoleClaim = "groups";
|
|
this.DataClaims = [];
|
|
this.DataClaimPrefix = "jellyfin-";
|
|
this.UserRole = "jellyfin";
|
|
this.AdminRole = "jellyfin-admin";
|
|
this.AvatarUrlClaim = "picture";
|
|
this.AuthenticationTimeout = 5;
|
|
this.DefaultProvider = "Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider";
|
|
this.ValidateIssuerName = true;
|
|
this.LoadProfile = true;
|
|
this.CanonicalLinks = new SerializableDictionary<string, System.Guid>();
|
|
this.ReverseCanonicalLinks = new SerializableDictionary<System.Guid, string>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the provider is enabled.
|
|
/// </summary>
|
|
public bool Enabled { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the OpenID well-known information endpoint.
|
|
/// </summary>
|
|
public string Issuer { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets OpenID client ID.
|
|
/// </summary>
|
|
public string ClientId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets OpenID shared secret.
|
|
/// </summary>
|
|
public string ClientSecret { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or Sets additional Scopes to request access to in the authorization request.
|
|
/// </summary>
|
|
public string[] Scopes { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default username claim when creating new accounts.
|
|
/// </summary>
|
|
public string UsernameClaim { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the claim containing the URL of the user avatar.
|
|
/// </summary>
|
|
public string AvatarUrlClaim { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the claim to check roles against. Separated by "."s.
|
|
/// </summary>
|
|
public string RoleClaim { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the roles that are checked to determine whether the user is an administrator.
|
|
/// </summary>
|
|
public string AdminRole { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets what roles are checked to determine whether the user is allowed to use Jellyfin.
|
|
/// </summary>
|
|
public string UserRole { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets what claims are used to configure the user.
|
|
/// </summary>
|
|
public string[] DataClaims { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets what claims are used to configure the user.
|
|
/// </summary>
|
|
public string DataClaimPrefix { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether RBAC is enabled.
|
|
/// </summary>
|
|
public bool EnableAuthorization { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default provider the user after logging in with OIDC.
|
|
/// </summary>
|
|
public string DefaultProvider { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the redirect port override.
|
|
/// </summary>
|
|
public int? PortOverride { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a mapping of canonical names from the provider to jellyfin user ids.
|
|
/// </summary>
|
|
[System.Xml.Serialization.XmlElementAttribute("CanonicalLinks")]
|
|
public SerializableDictionary<string, System.Guid> CanonicalLinks { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a mapping of canonical names from the provider to jellyfin user ids.
|
|
/// </summary>
|
|
[System.Xml.Serialization.XmlElementAttribute("ReverseCanonicalLinks")]
|
|
public SerializableDictionary<System.Guid, string> ReverseCanonicalLinks { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether pushed authorization is required.
|
|
/// </summary>
|
|
public bool PushedAuthorization { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the OpenID endpoints are validated.
|
|
/// </summary>
|
|
public bool ValidateEndpoints { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the OpenID issuer name is validated.
|
|
/// </summary>
|
|
public bool ValidateIssuerName { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets Amount of time in minutes to wait for a user to finish OIDC Authentication.
|
|
/// </summary>
|
|
public int AuthenticationTimeout { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the UserInfo endpoint is used to get profile data.
|
|
/// Data from UserInfo endpoint is merged with ID Token.
|
|
/// </summary>
|
|
public bool LoadProfile { get; set; }
|
|
|
|
/// <summary>
|
|
/// Creates a link for a user. Refuses to change a user that already has a link.
|
|
/// </summary>
|
|
/// <param name="jellyfinUserId">The user ID within jellyfin to link to the provider.</param>
|
|
/// <param name="providerUserId">The user ID from this provider.</param>
|
|
/// <returns>Whether this API endpoint succeeded.</returns>
|
|
public (bool, string) CreateCanonicalLink(System.Guid jellyfinUserId, string providerUserId) {
|
|
System.Guid existingUser;
|
|
string existingLink;
|
|
if (this.CanonicalLinks.TryGetValue(providerUserId, out existingUser)) {
|
|
return (existingUser == jellyfinUserId, "OIDC User is already linked in this provider");
|
|
}
|
|
if (this.ReverseCanonicalLinks.TryGetValue(jellyfinUserId, out existingLink)) {
|
|
return (existingLink == providerUserId, "JellyFin User is already linked in this provider");
|
|
}
|
|
|
|
this.CanonicalLinks[providerUserId] = jellyfinUserId;
|
|
this.ReverseCanonicalLinks[jellyfinUserId] = providerUserId;
|
|
OIDCPlugin.Instance.UpdateConfiguration(OIDCPlugin.Instance.Configuration);
|
|
return (true, string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fixes missing ReverseCanonicalLinks.
|
|
/// </summary>
|
|
public void FixCanonicalLinks() {
|
|
System.Collections.Generic.HashSet<System.Guid> found = [];
|
|
System.Collections.Generic.HashSet<string> toRemove = [];
|
|
foreach (var link in this.CanonicalLinks) {
|
|
if (found.Contains(link.Value)) {
|
|
toRemove.Add(link.Key);
|
|
}
|
|
found.Add(link.Value);
|
|
this.ReverseCanonicalLinks.TryAdd(link.Value, link.Key);
|
|
}
|
|
foreach (var duplicate in toRemove) {
|
|
this.CanonicalLinks.Remove(duplicate);
|
|
}
|
|
}
|
|
}
|