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
560 stars 27 forks source link

Error processing request. URL GET /sso/OID/r/authentik. #165

Closed DesertCookie closed 6 months ago

DesertCookie commented 6 months ago

I don't see to be able to log in. The redirect from Authentik back to Jellyfin times out with its call such as https://example.com/sso/OID/r/authentik?code=986a34064537407f841cf8ebb4cfba4b&state=vlpfRK6TPd9CmJq1gbwXsg.

In Jellyfin, I get this error:

[20:35:54] [ERR] [23] Jellyfin.Server.Middleware.ExceptionMiddleware: Error processing request. URL GET /sso/OID/r/authentik.
System.ArgumentNullException: Value cannot be null. (Parameter 'key')
   at System.Collections.Generic.Dictionary`2.FindValue(TKey key)
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Jellyfin.Plugin.SSO_Auth.Api.SSOController.OidPost(String provider, String state)
   at lambda_method702(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(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 Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Jellyfin.Server.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Server.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
   at Jellyfin.Server.Middleware.IpBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager)
   at Jellyfin.Server.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Server.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.Server.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
   at Jellyfin.Server.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Jellyfin.Server.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context, IServerConfigurationManager serverConfigurationManager)
   at Jellyfin.Server.Middleware.ExceptionMiddleware.Invoke(HttpContext context)

Here's my OpenID configuration:

{
  "issuer": "https://auth.example.com/application/o/jellyfin/",
  "authorization_endpoint": "https://auth.example.com/application/o/authorize/",
  "token_endpoint": "https://auth.example.com/application/o/token/",
  "userinfo_endpoint": "https://auth.example.com/application/o/userinfo/",
  "end_session_endpoint": "https://auth.example.com/application/o/jellyfin/end-session/",
  "introspection_endpoint": "https://auth.example.com/application/o/introspect/",
  "revocation_endpoint": "https://auth.example.com/application/o/revoke/",
  "device_authorization_endpoint": "https://auth.example.com/application/o/device/",
  "response_types_supported": [
    "code",
    "id_token",
    "id_token token",
    "code token",
    "code id_token",
    "code id_token token"
  ],
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "jwks_uri": "https://auth.example.com/application/o/jellyfin/jwks/",
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "implicit",
    "client_credentials",
    "password",
    "urn:ietf:params:oauth:grant-type:device_code"
  ],
  "id_token_signing_alg_values_supported": [
    "HS256"
  ],
  "subject_types_supported": [
    "public"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "acr_values_supported": [
    "goauthentik.io/providers/oauth2/default"
  ],
  "scopes_supported": [
    "profile",
    "openid",
    "email",
    "jf-groups"
  ],
  "request_parameter_supported": false,
  "claims_supported": [
    "sub",
    "iss",
    "aud",
    "exp",
    "iat",
    "auth_time",
    "acr",
    "amr",
    "nonce",
    "email",
    "email_verified",
    "name",
    "given_name",
    "preferred_username",
    "nickname",
    "groups"
  ],
  "claims_parameter_supported": false,
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

I originally though about using Authentik with SAML as I already do that for Nextcloud. However, I was unsure about how to do that with this plugin.

9p4 commented 6 months ago

Can you upload the Jellyfin plugin configuration as an XML file here?

DesertCookie commented 6 months ago

Where can I findWhere can I find that file?

9p4 commented 6 months ago

It should be in your Jellyfin configuration folder under plugins as SSO-Auth.xml

DesertCookie commented 6 months ago

I only have a folder configurations in there that contains Jellyfin.Plugin.MusicBrainz.xml. whereis also doesn't give me any results.

Edit: I've searched in the container itself too, in case I overlooked a mounting point, but it does not contain any such file either.

9p4 commented 6 months ago

How did you configure the Jellyfin plugin? How are you starting the login flow?

DesertCookie commented 6 months ago

I've set everything via the Plugin settings in the GUI. I've added the button to the login page that redirects to https://jf.example.de/sso/OID/p/authentik.

9p4 commented 6 months ago

Can you at least send a screenshot of the plugin configuration if you cannot find the XML configuration? Please redact any sensitive information.

DesertCookie commented 6 months ago

Everything not shown is either empty or at default values.

01 02

9p4 commented 6 months ago

Can you change the endpoint to not include .well-known/openid-configuration?

DesertCookie commented 6 months ago

That seems to return the same values and exhibit a similar behaviour - minus the error in the logs. Now I only get this (the timeout is still present as before):

[22:08:37] [INF] [8] Emby.Server.Implementations.IO.LibraryMonitor: Watching directory /media/.fernsehen
[22:09:27] [INF] [13] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[22:09:36] [WRN] [15] Jellyfin.Server.Middleware.ResponseTimeMiddleware: Slow HTTP Response from http://jf.example.com/sso/OID/p/authentik? to 10.10.10.205 in 0:00:08.4992387 with Status Code 302
[22:09:38] [INF] [15] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[22:09:48] [INF] [28] Emby.Server.Implementations.HttpServer.WebSocketManager: WS 10.10.10.205 request
[22:09:58] [INF] [17] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[22:09:59] [INF] [26] Jellyfin.Plugin.SSO_Auth.Api.SSOController: Is request linking: False
[22:09:59] [WRN] [26] Jellyfin.Server.Middleware.ResponseTimeMiddleware: Slow HTTP Response from http://jf.example.com/sso/OID/r/authentik?code=4e463964f67a4fc388fdff43ef44425e&state=SEk_l4Pl1oY-tZvHL14QKQ to 10.10.10.205 in 0:00:20.1957626 with Status Code 200
[22:10:03] [WRN] [17] Jellyfin.Server.Middleware.ResponseTimeMiddleware: Slow HTTP Response from http://jf.example.com/sso/OID/p/authentik? to 10.10.10.205 in 0:00:05.1294845 with Status Code 302
[22:10:36] [INF] [28] Emby.Server.Implementations.Session.SessionWebSocketListener: Sending ForceKeepAlive message to 1 inactive WebSockets.
[22:10:46] [INF] [21] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[22:10:48] [INF] [21] Emby.Server.Implementations.Session.SessionWebSocketListener: Lost 1 WebSockets.
[22:11:07] [INF] [27] Jellyfin.Plugin.SSO_Auth.Api.SSOController: Is request linking: False
[22:11:07] [WRN] [27] Jellyfin.Server.Middleware.ResponseTimeMiddleware: Slow HTTP Response from http://jf.example.com/sso/OID/r/authentik?code=8ae95b7d1bac4a3d9295264cb928514c&state=fvnpZctXqwVQaoJ3OxwFAg to 10.1.1.205 in 0:00:20.7885438 with Status Code 200
9p4 commented 6 months ago

Is there no https on your Jellyfin instance?

DesertCookie commented 6 months ago

It is via Cloudflare behind Nginx Proxy Manager. However, I assume my router detects that my URL points back to itself and directly redirects within my home network, thus showing local IP addresses.

9p4 commented 6 months ago

Can you please send me your Authentik configuration (and please try to find the SSO-Auth.xml file as well) so I can try to reproduce your error?

DesertCookie commented 6 months ago

authentik application authentik provider authentik provider 2

I really cannot find the file anywhere in my Jellyfin container (similar story for most other plugins of which I have about a dozen installed).

no sso-auth

9p4 commented 6 months ago

Can you try running find / -type f -name SSO-Auth.xml in the container?

Also, what container platform are you using?

DesertCookie commented 6 months ago

I run unRAID 6.12.6.

Here's the output of your command:

root@d5662063bd00:/# find / -type f -name SSO-Auth.xm
find: ‘/proc/176/task/176/fdinfo’: Permission denied
find: ‘/proc/176/task/196/fdinfo’: Permission denied
find: ‘/proc/176/task/200/fdinfo’: Permission denied
find: ‘/proc/176/task/202/fdinfo’: Permission denied
find: ‘/proc/176/task/203/fdinfo’: Permission denied
find: ‘/proc/176/task/204/fdinfo’: Permission denied
find: ‘/proc/176/task/206/fdinfo’: Permission denied
find: ‘/proc/176/task/207/fdinfo’: Permission denied
find: ‘/proc/176/task/208/fdinfo’: Permission denied
find: ‘/proc/176/task/213/fdinfo’: Permission denied
find: ‘/proc/176/task/214/fdinfo’: Permission denied
find: ‘/proc/176/task/216/fdinfo’: Permission denied
find: ‘/proc/176/task/218/fdinfo’: Permission denied
find: ‘/proc/176/task/241/fdinfo’: Permission denied
find: ‘/proc/176/task/242/fdinfo’: Permission denied
find: ‘/proc/176/task/309/fdinfo’: Permission denied
find: ‘/proc/176/task/465/fdinfo’: Permission denied
find: ‘/proc/176/task/478/fdinfo’: Permission denied
find: ‘/proc/176/task/480/fdinfo’: Permission denied
find: ‘/proc/176/task/481/fdinfo’: Permission denied
find: ‘/proc/176/task/482/fdinfo’: Permission denied
find: ‘/proc/176/task/486/fdinfo’: Permission denied
find: ‘/proc/176/task/487/fdinfo’: Permission denied
find: ‘/proc/176/task/488/fdinfo’: Permission denied
find: ‘/proc/176/map_files’: Permission denied
find: ‘/proc/176/fdinfo’: Permission denied
find: ‘/sys/kernel/slab’: Input/output error
9p4 commented 6 months ago

What is your Jellyfin unRaid configuration? If you restart the Jellyfin container in unRaid, does the plugin get uninstalled?

DesertCookie commented 6 months ago

That's an interesting question. Since linuxserver's image seems to keep everything in /config though and I have mapped that, the plugin install should persist:

docker run
  -d
  --name='Jellyfin'
  --net='eth0'
  --ip='10.1.1.206'
  -e TZ="Europe/Berlin"
  ...
  -e 'TCP_PORT_8096'='8096'
  -e 'TCP_PORT_8920'='8920'
  -e 'UDP_PORT_7359'='7359'
  -e 'UDP_PORT_1900'='1900'
  ...
  -v '/mnt/user/Jellyfin':'/media':'rw'
  -v '/mnt/cache/appdata/Jellyfin':'/config':'rw'
  --restart=always 'lscr.io/linuxserver/jellyfin:latest' 
9p4 commented 6 months ago

Is there anything in /mnt/cache/appdata/Jellyfin? (Also, that cache better not be being cleared. Jellyfin configuration is meant to be persistent! There are meant to be separate cache and configuration folders: take a look at https://jellyfin.org/docs/general/installation/container).

DesertCookie commented 6 months ago

The data in /mnt/cache/appdata/Jellyfin on my host system is the exact same as in the screenshot from my whereis command above.

cache on unRAID only refers to a specific path in how the filesystem is set up and does persist! In unRAID, you have all the drives accessible via /mnt/diskX/ and the entire "RAID" via /mnt/user/; /mnt/cache/ is simply a short form of the latter that directly accesses the SSD that acts as a cache for the HDDs in the array; it holds all Docker data, VM volumes, and the most recent files (those are moved to the array on a schedule, while Docker and VM data stay on the SSD cache permanently for performance reasons).

9p4 commented 6 months ago

Can you try the official Jellyfin image?

DesertCookie commented 6 months ago

I have created a new Jellyfin instance with the stock container. Sadly, I was unable to get the existing database to run as I kept getting SQLLight errors about how the database could not be read.

I also created a new Provider and Application for this Jellyfin2 that successfully logs in:

[19:53:44] [INF] [26] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[19:53:44] [INF] [26] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO user akadmin doesn't exist, creating...
[19:53:44] [INF] [26] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO user link doesn't exist, creating...
[19:53:44] [INF] [26] Jellyfin.Plugin.SSO_Auth.Api.SSOController: Auth request created...
[19:53:44] [INF] [26] Emby.Server.Implementations.Session.SessionManager: Current/Max sessions for user akadmin: 0/0
[19:53:44] [INF] [26] Emby.Server.Implementations.Session.SessionManager: Creating new access token for user a0578b06-5b6a-47f2-xxxx-xxxxxxxxxxxx
[19:53:44] [WRN] [26] Jellyfin.Server.Implementations.Users.UserManager: User akadmin was found with invalid/missing Authentication Provider Jellyfin.Plugin.SSO_Auth.Api.SSOController. Assigning user to InvalidAuthProvider until this is corrected
[19:53:45] [WRN] [26] Jellyfin.Server.Implementations.Users.UserManager: User akadmin was found with invalid/missing Authentication Provider Jellyfin.Plugin.SSO_Auth.Api.SSOController. Assigning user to InvalidAuthProvider until this is corrected
[19:53:45] [INF] [26] Emby.Server.Implementations.HttpServer.WebSocketManager: WS 10.1.1.100 request
[19:53:55] [WRN] [21] Jellyfin.Server.Implementations.Users.UserManager: User akadmin was found with invalid/missing Authentication Provider Jellyfin.Plugin.SSO_Auth.Api.SSOController. Assigning user to InvalidAuthProvider until this is corrected
[19:53:57] [WRN] [23] Jellyfin.Server.Implementations.Users.UserManager: User akadmin was found with invalid/missing Authentication Provider Jellyfin.Plugin.SSO_Auth.Api.SSOController. Assigning user to InvalidAuthProvider until this is corrected
[19:53:57] [WRN] [21] Jellyfin.Server.Implementations.Users.UserManager: User akadmin was found with invalid/missing Authentication Provider Jellyfin.Plugin.SSO_Auth.Api.SSOController. Assigning user to InvalidAuthProvider until this is corrected

I'm unsure of how to continue from here. I definitely could spin up a new Jellyfin instance and reimport all my stuff if I really wanted SSO to work for this. However, if I could avoid setting up all of my settings and plugins again, I'd chose that path. I do see though that this is more likely a Jellyfin / image issue and not one with your plugin. Perhaps one question should I decide to set up a new Jellyfin instance: Does OpenID or SAML make more sense to you? I use the latter for Nextcloud and thus am worrying that using two systems for my different services might be unnecessarily complicated.

9p4 commented 6 months ago

I don't have strong opinions either way. There is more interest in OIDC, so the plugin's features with OIDC are better tested. I implemented SAML because it was an easy proof-of-concept when first developing the plugin compared to OIDC's complexity.

The plugin only has a GUI for OIDC, so if that matters to you, use OIDC.

DesertCookie commented 6 months ago

Do you happen to have a template configuration file for SAML? I can only find the API way to add a provider. That does not work for me however, reporting 405 Method Not Allowed for POST.

9p4 commented 6 months ago

There is only the API way to add the provider for SAML. What command are you using to configure the provider?

DesertCookie commented 6 months ago

This is what I have attempted:

curl -v -X POST -H "Content-Type: application/json" -d '{"samlEndpoint": "https://auth.´myDomain.url/application/saml/jellyfin2/sso/binding/post/", "samlClientId": "saml-jellyfin", "samlCertificate": "extremelyLongRSACertificateFromAuthentikThatISetAsTheSigningCertificate", "enabled": true, "enableAuthorization": true, "enableAllFolders": false, "enabledFolders": [], "adminRoles": ["jellyfin-admin"], "roles": ["jellyfin"], "enableFolderRoles": true, "folderRoleMapping": [{"role": "allowed-to-watch-movies", "folders": ["cc7df17e2f3509a4b5fc1d1ff0a6c4d0", "f137a2dd21bbc1b99aa5c0f6bf02a805"]}]}' "http://myJellyfin.url/sso/SAML/Add/authentik?api_key=myJellyfinAPIKey"

The folders I just copied from your example. I wanted to test if it would go through at all.

This is the output from Windows terminal:

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying [2606:4700:3035::xxxx:xxxx]:443...
* Connected to auth.myDomain.url (2606:4700:3035::xxxx:xxxx) port 443
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* ALPN: server accepted http/1.1
* using HTTP/1.1
> POST /application/saml/jellyfin2/sso/binding/post/, HTTP/1.1
> Host: auth.turningheadsfilme.de
> User-Agent: curl/8.4.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 15
>
* schannel: remote party requests renegotiation
* schannel: renegotiating SSL/TLS connection
* schannel: SSL/TLS connection renegotiated
< HTTP/1.1 405 Method Not Allowed
< Date: Mon, 19 Feb 2024 23:08:20 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< allow: GET, HEAD, OPTIONS
< referrer-policy: same-origin
< vary: Accept-Encoding
< vary: Cookie
< x-authentik-id: 68955ac9d557448cab086852eed5891f
< x-content-type-options: nosniff
< x-frame-options: DENY
< x-powered-by: authentik
< strict-transport-security: max-age=63072000;includeSubDomains; preload
< CF-Cache-Status: DYNAMIC
< Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=d3RFqHGVNe2HtLCMXN%2Fip5BpNpwuELbR%2F7qi1s0stDgs9H8CyjCNbdikA9g5DU8iftEDcF7QLh2z8x3o3OPvJWZk8qSnq9ZHhTXYdqpVg0Jgw98uhPyF4o2cI8WjHJIoXqQSX%2BIqqkOx1PZHPRyIR1tip7VCeguT"}],"group":"cf-nel","max_age":604800}
< NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< Server: cloudflare
< CF-RAY: 85822bce8bd907fb-IAD
< alt-svc: h3=":443"; ma=86400
<
* Connection #0 to host auth.turningheadsfilme.de left intact
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Bad hostname
* Closing connection
curl: (3) URL rejected: Bad hostname
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Bad hostname
* Closing connection
curl: (3) URL rejected: Bad hostname
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Bad hostname
* Closing connection
curl: (3) URL rejected: Bad hostname
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Bad hostname
* Closing connection
curl: (3) URL rejected: Bad hostname
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Bad hostname
* Closing connection
curl: (3) URL rejected: Bad hostname
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
Note: Unnecessary use of -X or --request, POST is already inferred.
* URL rejected: Port number was not a decimal number between 0 and 65535
* Closing connection
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
curl: (3) bad range in URL position 2:
[jellyfin-admin],
 ^
9p4 commented 6 months ago

There seems to be some misquoting happening in Powershell/Batch. Can you run this in Git Bash or some other Unix-like shell?

DesertCookie commented 5 months ago

Sorry, got no email that you had commented.

It worked from a Linux terminal. I now have the following config:

<?xml version="1.0" encoding="utf-8"?>
<PluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SamlConfigs>
    <item>
      <key>
        <string>authentik</string>
      </key>
      <value>
        <PluginConfiguration>
          <SamlEndpoint>https://auth.myURL.com/application/saml/jellyfinthf/sso/binding/post/</SamlEndpoint>
          <SamlClientId>jellyfinthf-saml</SamlClientId>
          <SamlCertificate>extremelyLongRSACertificateFromAuthentikThatISetAsTheSigningCertificate</SamlCertificate>          
         <Enabled>true</Enabled>
          <EnableAuthorization>true</EnableAuthorization>
          <EnableAllFolders>false</EnableAllFolders>
          <EnabledFolders />
          <AdminRoles>
            <string>jellyfin-admin</string>
          </AdminRoles>
          <Roles>
            <string>jellyfin</string>
          </Roles>
          <EnableFolderRoles>true</EnableFolderRoles>
          <EnableLiveTvRoles>false</EnableLiveTvRoles>
          <EnableLiveTv>false</EnableLiveTv>
          <EnableLiveTvManagement>false</EnableLiveTvManagement>
          <FolderRoleMappings>
            <FolderRoleMappings>
              <Role>allowed-to-watch-movies</Role>
              <Folders>
                <string>cc7df17e2f3509a4b5fc1d1ff0a6c4d0</string>
                <string>f137a2dd21bbc1b99aa5c0f6bf02a805</string>
              </Folders>
            </FolderRoleMappings>
          </FolderRoleMappings>
          <NewPath>false</NewPath>
          <CanonicalLinks />
        </PluginConfiguration>
      </value>
    </item>
  </SamlConfigs>
  <OidConfigs />
</PluginConfiguration>

When trying to access myJellyfin.com/sso/OID/start/authentik I get Error processing request. and the following in the Jellyfin log:

[20:55:33] [ERR] [39] Jellyfin.Server.Middleware.ExceptionMiddleware: Error processing request. URL GET /sso/OID/start/authentik.
System.ArgumentException: Provider does not exist
   at Jellyfin.Plugin.SSO_Auth.Api.SSOController.OidChallenge(String provider, Boolean isLinking)
   at lambda_method1008(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(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 Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Jellyfin.Server.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Server.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
   at Jellyfin.Server.Middleware.IpBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager)
   at Jellyfin.Server.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Server.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.Server.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
   at Jellyfin.Server.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Jellyfin.Server.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context, IServerConfigurationManager serverConfigurationManager)
   at Jellyfin.Server.Middleware.ExceptionMiddleware.Invoke(HttpContext context)
9p4 commented 5 months ago

If you are using SAML, you need to go to "/sso/SAML/p/authentik"

DesertCookie commented 5 months ago

Thanks, that was stupid.

Now I'm stuck on getting a bad request from Authentik; the SAML payload is missing. However, I don't think that's actually the case. The Jellyfin log says: SAML user: xyz has insufficient roles: []. Expected any one of: ["jellyfin"] and Error. Check permissions. when accessing Jellyfin from the Authentik dashboard. The tested account definitely has that role in Authenik, though. Authentik returns the groups as this schema. In Nextcloud and WordPress I had to add this link for attribute mapping purposes - is there such an option within this plugin?

I have added a SAML property mapping for groups within Authentik following your provider documentation (for OID). I am unsure of how to set these options on the plugin-side.

Edit: I got rid of the SAML payload error by using Authentik's SSO URL (IdP-initiated Login) instead of the regular post or redirect URLs that I got accustomed to using with all other apps in my suite.

9p4 commented 5 months ago

To confirm, you are starting the flow by going to the /start/ or /p/ URLs, right?

DesertCookie commented 5 months ago

I am.

9p4 commented 5 months ago

I think you need to set the SAML mapper to be named "Role". Maybe this should be user-configurable.