9p4 / jellyfin-plugin-sso

This plugin allows users to sign in through an SSO provider (such as Google, Microsoft, or your own provider). This enables one-click signin.
GNU General Public License v3.0
593 stars 27 forks source link

SSO login not working after changing username #146

Open mardom1 opened 1 year ago

mardom1 commented 1 year ago

Describe the bug I have an existing Jellyfin user account and an Authentik account. Jellyfin SSO plugin is setup for OpenID. The usernames are different. Two (probably related) issues:

  1. When I go to the self service page and try to link the accounts, the authentication succeeds, but creates a new user instead of linking it to my existing one.
  2. If I change my Jellyfin username to match the one in Authentik, the linking works as expected. However, if I then change the username in Jellyfin back and try to login via SSO again, a new user gets created, even though the self service page still shows the SSO account as linked.

To Reproduce Steps to reproduce the behavior:

  1. Set Jellyfin username to match OID one.
  2. Link accounts using self-service page.
  3. Change Jellyfin username to something different.
  4. Logout
  5. Login via SSO
  6. You are now logged in as a newly created user matching the SSO username.

Expected behavior Be logged in as the already linked user.

Screenshots Not needed.

Configuration Not needed.

Versions (please complete the following information):

9p4 commented 1 year ago

https://github.com/9p4/jellyfin-plugin-sso/issues/75

9p4 commented 1 year ago

If you set the preferred claim to "sub", it'll work automatically. It will make the usernames in Jellyfin ugly, though.

9p4 commented 1 year ago

Perhaps linking can be expanded so that it maps sub to a username.

mardom1 commented 1 year ago

That does not solve it for me. Still unlinks once the Jellyfin username gets changed by an admin. I thought that this was possible:

If users are registered using this plugin using a provider that doesnt support friendly names, such as a google, the username of the new account will still be numeric, however, an admin can now change the username to something better manually afterwards, and the linking will be intact (https://github.com/9p4/jellyfin-plugin-sso/pull/34)

Is the SSO user mapped to the Jellyfin username or to the Jellyfin UID?

9p4 commented 1 year ago

When linking, the SSO username claim is mapped to Jellyfin's user UID.

9p4 commented 1 year ago

Ideally, we can switch to using sub internally and use the linking logic everywhere

mardom1 commented 1 year ago

After looking into the code, it seems this line is the culprit:

https://github.com/9p4/jellyfin-plugin-sso/blob/1b6761bf7337253b650e545e617c8ea41f988f8a/SSO-Auth/Api/SSOController.cs#L718

As I understand it, it only works when the canonicalName is equal to the Jellyfin username, regardless of any CanonicalLinks. Shouldn't the canonicalName be mapped to the Jellyfin user UID using the CanonicalLinks and that UID looked up using GetUserById?

9p4 commented 1 year ago

Yes, that is on the roadmap. It isn't implemented quite yet.

Dark3clipse commented 4 months ago

I have accidentally renamed my user account, and then a new user with the old name was created by this plugin. I removed that user. Now my sso is no longer working.

[22:09:33] [ERR] [41] Jellyfin.Api.Middleware.ExceptionMiddleware: Error processing request. URL POST /sso/OID/Auth/keycloak.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Jellyfin.Plugin.SSO_Auth.Api.SSOController.Authenticate(Guid userId, Boolean isAdmin, Boolean enableAuthorization, Boolean enableAllFolders, String[] enabledFolders, Boolean enableLiveTv, Boolean enableLiveTvAdmin, AuthResponse authResponse, String defaultProvider)
   at Jellyfin.Plugin.SSO_Auth.Api.SSOController.OidAuth(String provider, AuthResponse response)
   at lambda_method1128(Closure, Object)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Prometheus.HttpMetrics.HttpRequestDurationMiddleware.Invoke(HttpContext context)
   at Prometheus.HttpMetrics.HttpRequestCountMiddleware.Invoke(HttpContext context)
   at Prometheus.HttpMetrics.HttpInProgressMiddleware.Invoke(HttpContext context)
   at Jellyfin.Api.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Api.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
   at Jellyfin.Api.Middleware.IPBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager)
   at Jellyfin.Api.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Api.Middleware.QueryStringDecodingMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.ReDoc.ReDocMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Api.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
   at Jellyfin.Api.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Jellyfin.Api.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context, IServerConfigurationManager serverConfigurationManager)
   at Jellyfin.Api.Middleware.ExceptionMiddleware.Invoke(HttpContext context)

How can I make it working again?

9p4 commented 4 months ago

Stop Jellyfin, and edit the SSO-Auth.xml configuration file. Change the username in the linked accounts section, and start Jellyfin.