mirror of
https://github.com/9p4/jellyfin-plugin-sso
synced 2026-10-19 21:56:06 +11:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f86ce5101 | |||
| d2c77db404 | |||
| fc3976dcc8 | |||
| fc58b8e80f | |||
| da21ebffa3 | |||
| 0d18ebae03 | |||
| 77e2a229f2 | |||
| 71bb9a2f14 | |||
| 8baa922eea | |||
| 0738ad85f7 | |||
| 8d049705c4 | |||
| 3459baffdf | |||
| de6cd5d5c2 | |||
| 299d3436ec | |||
| 5808f34064 | |||
| 5ed4c8bbcc | |||
| f78a0f3108 | |||
| aa0e361265 | |||
| efc997c39e | |||
| caab66b653 | |||
| 79ac628c4c | |||
| fe3ca6337d | |||
| f761dea356 | |||
| 55f58ecedd | |||
| 556feba864 | |||
| 1f08ccd213 | |||
| f1f57723c3 |
@@ -3,12 +3,12 @@ on:
|
||||
inputs:
|
||||
dotnet-version:
|
||||
required: false
|
||||
default: "8.0.x"
|
||||
default: "9.0.x"
|
||||
description: "The .NET version to setup for the build"
|
||||
type: string
|
||||
dotnet-target:
|
||||
required: false
|
||||
default: "net8.0"
|
||||
default: "net9.0"
|
||||
description: "The .NET target to set for JPRM"
|
||||
type: string
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
dotnet-target: "${{ inputs.dotnet-target }}"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag=v4.6.2
|
||||
with:
|
||||
name: build-artifact
|
||||
retention-days: 30
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build Dotnet
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
version: "0.0.0.9000"
|
||||
verbosity: debug
|
||||
path: .
|
||||
dotnet-target: "net8.0"
|
||||
dotnet-target: "net9.0"
|
||||
output: _dist
|
||||
- name: Prepare GitHub Release assets
|
||||
run: |-
|
||||
|
||||
@@ -10,15 +10,15 @@ jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
dotnet-version: "8.0.*"
|
||||
dotnet-target: "net8.0"
|
||||
dotnet-version: "9.0.*"
|
||||
dotnet-target: "net9.0"
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v2.1.0
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: build-artifact
|
||||
- name: Prepare GitHub Release assets
|
||||
|
||||
@@ -34,7 +34,7 @@ This is 100% alpha software! PRs are welcome to improve the code.
|
||||
|
||||
~~There is NO admin configuration! You must use the API to configure the program!~~ Added by [strazto](https://github.com/strazto) in PR [#18](https://github.com/9p4/jellyfin-plugin-sso/pull/18) and [#27](https://github.com/9p4/jellyfin-plugin-sso/pull/27).
|
||||
|
||||
**[This is for Jellyfin 10.8](https://github.com/9p4/jellyfin-plugin-sso/issues/3) and only on the Web UI and clients supporting [Quick Connect](https://jellyfin.org/docs/general/server/quick-connect)**
|
||||
**[This is for Jellyfin >=10.8](https://github.com/9p4/jellyfin-plugin-sso/issues/3) and only on the Web UI or clients supporting [Quick Connect](https://jellyfin.org/docs/general/server/quick-connect)**
|
||||
|
||||
**This README reflects the branch it is currently on! Switch tags to view version-specific documentation!**
|
||||
|
||||
@@ -91,8 +91,6 @@ The nightly build may have new features unavailable in other builds, but **be wa
|
||||
|
||||
## Examples
|
||||
|
||||
**Note that you should add both "/r/" and "/redirect/" paths to your SSO provider's configuration!**
|
||||
|
||||
### Creating A Login Button On The Main Page
|
||||
|
||||
In the Jellyfin administration UI, under "General", there is a "Branding" section. In that section, add the following code in the "Login disclaimer" block (replacing `PROVIDER_NAME` and the domain):
|
||||
@@ -311,7 +309,7 @@ Much thanks to the [Jellyfin LDAP plugin](https://github.com/jellyfin/jellyfin-p
|
||||
|
||||
I use the [AspNet SAML](https://github.com/jitbit/AspNetSaml/) library for the SAML side of things (patched to work with Base64 on non-Windows machines).
|
||||
|
||||
I use the [IdentityModel OIDC Client](https://github.com/IdentityModel/IdentityModel.OidcClient/) library for the OpenID side of things.
|
||||
I use the [Duende IdentityModel OIDC Client](https://github.com/DuendeSoftware/foss) library for the OpenID side of things.
|
||||
|
||||
Thanks to these projects, without which I would have been pulling my hair out implementing these protocols from scratch.
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Please email all security vulnerabilities and issues found to the email "contact at ersei dot net". If using LLMs/AI to find the issues, first verify the issue exists manually. Please do not publicly disclose security vulnerabilities until after a stable release for the fix has been released for 30 days.
|
||||
|
||||
The latest released version is the only supported version.
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data;
|
||||
using Jellyfin.Database.Implementations.Enums;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Duende.IdentityModel.OidcClient;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data;
|
||||
using Jellyfin.Database.Implementations.Entities;
|
||||
using Jellyfin.Database.Implementations.Enums;
|
||||
using Jellyfin.Plugin.SSO_Auth.Config;
|
||||
using Jellyfin.Plugin.SSO_Auth.Helpers;
|
||||
using MediaBrowser.Common.Api;
|
||||
@@ -772,7 +773,28 @@ public class SSOController : ControllerBase
|
||||
private async Task<Guid> CreateCanonicalLinkAndUserIfNotExist(string mode, string provider, string canonicalName)
|
||||
{
|
||||
User user = null;
|
||||
user = _userManager.GetUserByName(canonicalName);
|
||||
|
||||
// First try to get the user by its id in case it was already registered before
|
||||
Guid userId = Guid.Empty;
|
||||
try
|
||||
{
|
||||
userId = GetCanonicalLink(mode, provider, canonicalName);
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
userId = Guid.Empty;
|
||||
}
|
||||
|
||||
// No userId found? Let's try and find the user by name instead
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
user = _userManager.GetUserByName(canonicalName);
|
||||
}
|
||||
else
|
||||
{
|
||||
user = _userManager.GetUserById(userId);
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogInformation($"SSO user {canonicalName} doesn't exist, creating...");
|
||||
@@ -787,7 +809,7 @@ public class SSOController : ControllerBase
|
||||
UpdateCanonicalLinkConfig(links, mode, provider);
|
||||
}
|
||||
|
||||
Guid userId = Guid.Empty;
|
||||
userId = Guid.Empty;
|
||||
try
|
||||
{
|
||||
userId = GetCanonicalLink(mode, provider, canonicalName);
|
||||
|
||||
@@ -600,7 +600,10 @@
|
||||
type="checkbox"
|
||||
class="sso-toggle"
|
||||
/>
|
||||
<span>Disable Pushed Authorization (Insecure)</span>
|
||||
<span
|
||||
>Disable Pushed Authorization (Insecure). May be needed
|
||||
for Authelia.</span
|
||||
>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription"></div>
|
||||
</div>
|
||||
@@ -651,16 +654,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="RoleClaim">Port Override</label>
|
||||
<input is="emby-input"
|
||||
id="PortOverride"
|
||||
type="text"
|
||||
class="sso-text" />
|
||||
<div class="fieldDescription">
|
||||
If the plugin is redirecting to an incorrect port, set this to
|
||||
the appropiate port
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="RoleClaim"
|
||||
>Port Override</label
|
||||
>
|
||||
<input
|
||||
is="emby-input"
|
||||
id="PortOverride"
|
||||
type="text"
|
||||
class="sso-text"
|
||||
/>
|
||||
<div class="fieldDescription">
|
||||
If the plugin is redirecting to an incorrect port, set this
|
||||
to the appropiate port
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
||||
@@ -61,14 +61,14 @@
|
||||
is="emby-linkbutton"
|
||||
href="https://github.com/9p4/jellyfin-plugin-sso"
|
||||
class="button-link"
|
||||
>help page</a
|
||||
>homepage</a
|
||||
>
|
||||
and
|
||||
<a
|
||||
is="emby-linkbutton"
|
||||
href="https://github.com/9p4/jellyfin-plugin-sso/projects/1"
|
||||
href="https://github.com/9p4/jellyfin-plugin-sso/issues"
|
||||
class="button-link"
|
||||
>roadmap
|
||||
>issue tracker
|
||||
</a>
|
||||
for more information.
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>SSO_Auth</RootNamespace>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>Jellyfin.Plugin.SSO_Auth</RootNamespace>
|
||||
<AssemblyVersion>3.5.2.4</AssemblyVersion>
|
||||
<FileVersion>3.5.2.4</FileVersion>
|
||||
<AssemblyVersion>4.0.0.3</AssemblyVersion>
|
||||
<FileVersion>4.0.0.3</FileVersion>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
@@ -30,8 +30,8 @@
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Duende.IdentityModel.OidcClient" Version="6.0.1" />
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.*-*" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.*-*" />
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.11.0" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.11.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Security.Cryptography.Xml" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class Response
|
||||
/// <param name="certificateBytes">The certificate formatted as an array of bytes.</param>
|
||||
public Response(byte[] certificateBytes)
|
||||
{
|
||||
_certificate = new X509Certificate2(certificateBytes);
|
||||
_certificate = X509CertificateLoader.LoadCertificate(certificateBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
+24
-5
@@ -1,3 +1,5 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Jellyfin.Plugin.SSO_Auth;
|
||||
|
||||
/// <summary>
|
||||
@@ -9,7 +11,16 @@ public static class WebResponse
|
||||
/// The shared HTML between all of the responses.
|
||||
/// </summary>
|
||||
public static readonly string Base = @"<!DOCTYPE html>
|
||||
<html><head><meta name='viewport' content='width=device-width, initial-scale=1'></head><body>
|
||||
<html><head>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<style>
|
||||
body {
|
||||
background: #101010;
|
||||
color: #d1cfce;
|
||||
font-family: Noto Sans, Noto Sans HK, Noto Sans JP, Noto Sans KR, Noto Sans SC, Noto Sans TC, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head><body>
|
||||
<p>Logging in...</p>
|
||||
<noscript>Please enable Javascript to complete the login</noscript>
|
||||
<script>
|
||||
@@ -404,6 +415,14 @@ const sleep = (milliseconds) => {
|
||||
/// <returns>A string with the HTML to serve to the client.</returns>
|
||||
public static string Generator(string data, string provider, string baseUrl, string mode, bool isLinking = false)
|
||||
{
|
||||
// Strip out the protocol (http:// or https://) and convert the domain to Punycode
|
||||
var idnMapping = new IdnMapping();
|
||||
var protocolSeparatorIndex = baseUrl.IndexOf("//");
|
||||
var protocol = baseUrl.Substring(0, protocolSeparatorIndex + 2);
|
||||
var domain = baseUrl.Substring(protocolSeparatorIndex + 2);
|
||||
var punycodeDomain = idnMapping.GetAscii(domain);
|
||||
var punycodeBaseUrl = protocol + punycodeDomain;
|
||||
|
||||
return Base + @"
|
||||
async function link(request) {
|
||||
const jfCredentialsString = localStorage.getItem(""jellyfin_credentials"");
|
||||
@@ -417,7 +436,7 @@ async function link(request) {
|
||||
if (jfUser == null) return;
|
||||
if (jfToken == null) return;
|
||||
|
||||
const url = '" + $"{baseUrl}/sso/{mode}/Link/{provider}/" + @"' + jfUser;
|
||||
const url = '" + $"{punycodeBaseUrl}/sso/{mode}/Link/{provider}/" + @"' + jfUser;
|
||||
|
||||
return new Promise(resolve => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
@@ -442,7 +461,7 @@ async function link(request) {
|
||||
|
||||
async function main() {
|
||||
localStorage.removeItem('jellyfin_credentials');
|
||||
document.getElementById('iframe-main').src = '" + baseUrl + @"/web/index.html';
|
||||
document.getElementById('iframe-main').src = '" + punycodeBaseUrl + @"/web/index.html';
|
||||
|
||||
var data = '" + data + @"';
|
||||
while (localStorage.getItem(""_deviceId2"") == null ||
|
||||
@@ -460,7 +479,7 @@ async function main() {
|
||||
|
||||
if (" + $"{isLinking}".ToLower() + @") await link(request);
|
||||
|
||||
var url = '" + baseUrl + "/sso/" + mode + "/Auth/" + provider + @"';
|
||||
var url = '" + punycodeBaseUrl + "/sso/" + mode + "/Auth/" + provider + @"';
|
||||
|
||||
let response = await new Promise(resolve => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
@@ -484,7 +503,7 @@ async function main() {
|
||||
jfCreds['Servers'][0]['UserId'] = responseJson['User']['Id'];
|
||||
localStorage.setItem('jellyfin_credentials', JSON.stringify(jfCreds));
|
||||
localStorage.setItem('enableAutoLogin', 'true');
|
||||
window.location.replace('" + baseUrl + @"/web/index.html');
|
||||
window.location.replace('" + punycodeBaseUrl + @"/web/index.html');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
+5
-3
@@ -1,9 +1,9 @@
|
||||
name: "SSO Authentication"
|
||||
guid: "505ce9d1-d916-42fa-86ca-673ef241d7df"
|
||||
imageUrl: "https://raw.githubusercontent.com/9p4/jellyfin-plugin-sso/main/img/logo.png"
|
||||
version: "3.5.2.4"
|
||||
targetAbi: "10.9.0.0"
|
||||
framework: "net8.0"
|
||||
version: "4.0.0.3"
|
||||
targetAbi: "10.11.0.0"
|
||||
framework: "net9.0"
|
||||
owner: "9p4"
|
||||
overview: "Authenticate users against an SSO provider."
|
||||
description: |
|
||||
@@ -15,6 +15,8 @@ artifacts:
|
||||
- "Duende.IdentityModel.OidcClient.dll"
|
||||
- "Duende.IdentityModel.dll"
|
||||
changelog: |
|
||||
4.0.0.0: Jellyfin 10.11
|
||||
3.5.3.0: Allow for OID-provided avatars, various bugfixes and workarounds
|
||||
3.5.2.4: Updates for Jellyfin 10.9
|
||||
3.5.2.3: Improve OpenID discovery policy security rules, fix iOS login bugs related to cache
|
||||
3.5.2.2: Fix linking page when using new paths
|
||||
|
||||
Generated
+3
-3
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1730768919,
|
||||
"narHash": "sha256-8AKquNnnSaJRXZxc5YmF/WfmxiHX6MMZZasRP6RRQkE=",
|
||||
"lastModified": 1760934318,
|
||||
"narHash": "sha256-/oUYsC0lUCBory65VK+UHqCCsCspbL1Vgfcf1KUYqVw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a04d33c0c3f1a59a2c1cb0c6e34cd24500e5a1dc",
|
||||
"rev": "87848bf0cc4f87717fc813a4575f07330c3e743c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
let pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
in {
|
||||
devShell.x86_64-linux =
|
||||
pkgs.mkShell { buildInputs = [ pkgs.nodePackages.prettier pkgs.dotnet-sdk_8 ]; };
|
||||
pkgs.mkShell { buildInputs = [ pkgs.nodePackages.prettier pkgs.dotnet-sdk_9 ]; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ authelia:
|
||||
OidSecret: <redacted>
|
||||
RoleClaim: groups
|
||||
OidScopes: ["groups"]
|
||||
DisablePushedAuthorization: true
|
||||
```
|
||||
|
||||
## authentik
|
||||
|
||||
Reference in New Issue
Block a user