mirror of
https://github.com/9p4/jellyfin-plugin-sso.git
synced 2026-09-19 13:12:19 +00:00
Added AvatarFormatUrl to programatically set avatar on SSO Connect with OIDC
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -12,14 +14,15 @@ using Jellyfin.Plugin.SSO_Auth.Config;
|
||||
using Jellyfin.Plugin.SSO_Auth.Helpers;
|
||||
using MediaBrowser.Common.Api;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -38,6 +41,8 @@ public class SSOController : ControllerBase
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
private readonly ILogger<SSOController> _logger;
|
||||
private readonly ICryptoProvider _cryptoProvider;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private static readonly IDictionary<string, TimedAuthorizeState> StateManager = new Dictionary<string, TimedAuthorizeState>();
|
||||
|
||||
/// <summary>
|
||||
@@ -48,13 +53,24 @@ public class SSOController : ControllerBase
|
||||
/// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
|
||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||
/// <param name="cryptoProvider">Instance of the <see cref="ICryptoProvider"/> interface.</param>
|
||||
public SSOController(ILogger<SSOController> logger, ISessionManager sessionManager, IUserManager userManager, IAuthorizationContext authContext, ICryptoProvider cryptoProvider)
|
||||
/// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
|
||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||
public SSOController(
|
||||
ILogger<SSOController> logger,
|
||||
ISessionManager sessionManager,
|
||||
IUserManager userManager,
|
||||
IAuthorizationContext authContext,
|
||||
ICryptoProvider cryptoProvider,
|
||||
IProviderManager providerManager,
|
||||
IServerConfigurationManager serverConfigurationManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
_userManager = userManager;
|
||||
_authContext = authContext;
|
||||
_cryptoProvider = cryptoProvider;
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_logger.LogInformation("SSO Controller initialized");
|
||||
}
|
||||
|
||||
@@ -117,6 +133,13 @@ public class SSOController : ControllerBase
|
||||
StateManager[state].EnableLiveTv = config.EnableLiveTv;
|
||||
StateManager[state].EnableLiveTvManagement = config.EnableLiveTvManagement;
|
||||
|
||||
if (config.AvatarUrlFormat is not null)
|
||||
{
|
||||
StateManager[state].AvatarURL = result.User.Claims.Aggregate(
|
||||
config.AvatarUrlFormat,
|
||||
(s, claim) => s.Contains($"@{{{claim.Type}}}") ? s.Replace($"@{{{claim.Type}}}", claim.Value) : s);
|
||||
}
|
||||
|
||||
foreach (var claim in result.User.Claims)
|
||||
{
|
||||
if (claim.Type == (config.DefaultUsernameClaim?.Trim() ?? "preferred_username"))
|
||||
@@ -421,7 +444,7 @@ public class SSOController : ControllerBase
|
||||
{
|
||||
Guid userId = await CreateCanonicalLinkAndUserIfNotExist("oid", provider, kvp.Value.Username);
|
||||
|
||||
var authenticationResult = await Authenticate(userId, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), kvp.Value.EnableLiveTv, kvp.Value.EnableLiveTvManagement, response, config.DefaultProvider?.Trim())
|
||||
var authenticationResult = await Authenticate(userId, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), kvp.Value.EnableLiveTv, kvp.Value.EnableLiveTvManagement, response, config.DefaultProvider?.Trim(), kvp.Value.AvatarURL)
|
||||
.ConfigureAwait(false);
|
||||
return Ok(authenticationResult);
|
||||
}
|
||||
@@ -686,7 +709,7 @@ public class SSOController : ControllerBase
|
||||
|
||||
Guid userId = await CreateCanonicalLinkAndUserIfNotExist("saml", provider, samlResponse.GetNameID());
|
||||
|
||||
var authenticationResult = await Authenticate(userId, isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), liveTv, liveTvManagement, response, config.DefaultProvider?.Trim())
|
||||
var authenticationResult = await Authenticate(userId, isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), liveTv, liveTvManagement, response, config.DefaultProvider?.Trim(), null)
|
||||
.ConfigureAwait(false);
|
||||
return Ok(authenticationResult);
|
||||
}
|
||||
@@ -1020,7 +1043,8 @@ public class SSOController : ControllerBase
|
||||
/// <param name="enableLiveTvAdmin">Determines whether live TV can be managed by this user.</param>
|
||||
/// <param name="authResponse">The client information to authenticate the user with.</param>
|
||||
/// <param name="defaultProvider">The default provider of the user to be set after logging in.</param>
|
||||
private async Task<AuthenticationResult> Authenticate(Guid userId, bool isAdmin, bool enableAuthorization, bool enableAllFolders, string[] enabledFolders, bool enableLiveTv, bool enableLiveTvAdmin, AuthResponse authResponse, string defaultProvider)
|
||||
/// <param name="avatarUrl">The new avatar url for the user.</param>
|
||||
private async Task<AuthenticationResult> Authenticate(Guid userId, bool isAdmin, bool enableAuthorization, bool enableAllFolders, string[] enabledFolders, bool enableLiveTv, bool enableLiveTvAdmin, AuthResponse authResponse, string defaultProvider, string avatarUrl)
|
||||
{
|
||||
User user = _userManager.GetUserById(userId);
|
||||
if (enableAuthorization)
|
||||
@@ -1033,6 +1057,36 @@ public class SSOController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
if (avatarUrl is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
var extension = avatarUrl.Split(".").Last();
|
||||
var stream = await client.GetStreamAsync(avatarUrl);
|
||||
if (user != null)
|
||||
{
|
||||
var userDataPath =
|
||||
Path.Combine(
|
||||
_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath,
|
||||
user.Username);
|
||||
if (user.ProfileImage is not null)
|
||||
{
|
||||
await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
user.ProfileImage = new ImageInfo(Path.Combine(userDataPath, "profile" + extension));
|
||||
|
||||
await _providerManager.SaveImage(stream, "image/" + extension, user.ProfileImage.Path)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
user.SetPermission(PermissionKind.EnableLiveTvAccess, enableLiveTv);
|
||||
user.SetPermission(PermissionKind.EnableLiveTvManagement, enableLiveTvAdmin);
|
||||
|
||||
@@ -1150,6 +1204,7 @@ public class TimedAuthorizeState
|
||||
IsLinking = false;
|
||||
EnableLiveTv = false;
|
||||
EnableLiveTvManagement = false;
|
||||
AvatarURL = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1197,4 +1252,9 @@ public class TimedAuthorizeState
|
||||
/// Gets or sets a value indicating whether the user is allowed to manage live TV.
|
||||
/// </summary>
|
||||
public bool EnableLiveTvManagement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the user avatar url.
|
||||
/// </summary>
|
||||
public string AvatarURL { get; set; }
|
||||
}
|
||||
|
||||
@@ -293,6 +293,11 @@ public class OidConfig
|
||||
/// </summary>
|
||||
public string DefaultUsernameClaim { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL format of the new user avatar.
|
||||
/// </summary>
|
||||
public string AvatarUrlFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether HTTPS in the discovery endpoint is required.
|
||||
/// </summary>
|
||||
|
||||
@@ -559,6 +559,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label
|
||||
class="inputLabel inputLabelUnfocused"
|
||||
for="AvatarUrlFormat"
|
||||
>Set avatar url format</label
|
||||
>
|
||||
<input
|
||||
is="emby-input"
|
||||
id="AvatarUrlFormat"
|
||||
type="text"
|
||||
class="sso-text"
|
||||
/>
|
||||
<div class="fieldDescription">
|
||||
The url of the avatar with sso variable format:
|
||||
example : <code>https://example.com/@{user_id}.png</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer">
|
||||
<label>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user